UICollectionView中的内存警告(带图像)

时间:2013-06-08 07:57:17

标签: memory-management afnetworking uicollectionview

我目前正在使用包含大量图像的UICollectionView。但是,它有时会在此视图中因内存警告而崩溃。我正在使用AFNetworking和UIImageView + AFNetworking类来通过setImageWithURL:方法设置图像。一个问题可能是缓存。我不确定AFNetworking是否处理图像缓存。无论如何,有没有办法在内存管理方面优化此代码?或者,如果我要在此视图控制器中实现didReceiveMemoryWarning方法,可以在此方法中添加什么?我为此集合视图附加了cellForItemAtIndexPath的代码。

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"RecipeCell" forIndexPath:indexPath];

// setting the image view for the cell using AFNetworking. Does this do caching automatically?
UIImageView *recipeImageView = (UIImageView *)[cell viewWithTag:6];
if (PRODUCTION) {
    [recipeImageView setImageWithURL:[[self.recipes objectAtIndex:indexPath.row] objectForKey:@"recipe_image"] placeholderImage:[UIImage imageNamed:@"default_recipe_picture.png"]];
} else {
    [recipeImageView setImageWithURL:[NSString stringWithFormat:@"http://localhost:5000/%@", [[self.recipes objectAtIndex:indexPath.row] objectForKey:@"recipe_image"]] placeholderImage:[UIImage imageNamed:@"default_recipe_picture.png"]];
}


// configure the back of the cell. fill all the info.
UITextView *recipeNameView = (UITextView *)[cell viewWithTag:8];
recipeNameView.text = [NSString stringWithFormat:@"%@", [[self.recipes objectAtIndex:indexPath.row] objectForKey:@"recipe_name"]];

UILabel *recipeNameLabel = (UILabel *)[cell viewWithTag:2];
recipeNameLabel.text = [NSString stringWithFormat:@"%@", [[self.recipes objectAtIndex:indexPath.row] objectForKey:@"recipe_name"]];

NSDictionary *user = [[self.recipes objectAtIndex:indexPath.row] objectForKey:@"user"];
UIButton *chefNameButton = (UIButton *)[cell viewWithTag:3];
[chefNameButton setTitle:[NSString stringWithFormat:@"%@ %@", [user objectForKey:@"first_name"], [user objectForKey:@"last_name"]] forState:UIControlStateNormal];

NSMutableArray *missingIngredientsStringArray = [[NSMutableArray alloc] init];
NSArray *missingIngredients = [[self.recipes objectAtIndex:indexPath.row] objectForKey:@"missing_ingredients"];
for (NSDictionary *missingIngredient in missingIngredients) {
    [missingIngredientsStringArray addObject:[missingIngredient objectForKey:@"name"]];
}
NSString *missingIngredientsString = [missingIngredientsStringArray componentsJoinedByString:@","];

UITextView *missingIngredientsView = (UITextView *)[cell viewWithTag:4];
missingIngredientsView.text = [NSString stringWithFormat:@"%u Missing Ingredients: %@", missingIngredients.count, missingIngredientsString];

// configure the front of the cell. chef name button and missing ingredients and likes on front view
UIButton *frontNameButton = (UIButton *)[cell viewWithTag:11];
[frontNameButton setTitle:[NSString stringWithFormat:@"%@ %@", [user objectForKey:@"first_name"], [user objectForKey:@"last_name"]] forState:UIControlStateNormal];
[frontNameButton sizeToFit];
frontNameButton.frame = CGRectMake(160 - [frontNameButton.titleLabel.text sizeWithFont:[UIFont boldSystemFontOfSize:13]].width - 7, frontNameButton.frame.origin.y, frontNameButton.frame.size.width, frontNameButton.frame.size.height);

UILabel *likesLabel = (UILabel *)[cell viewWithTag:9];
likesLabel.text = [NSString stringWithFormat:@"%@ likes", [[self.recipes objectAtIndex:indexPath.row] objectForKey:@"likes"]];

UIButton *missingIngredientsButton = (UIButton *)[cell viewWithTag:12];
[missingIngredientsButton setBackgroundImage:[UIImage imageNamed:@"badge_green.png"] forState:UIControlStateSelected];
if (missingIngredients.count == 0) {
    missingIngredientsButton.selected = YES;
    [missingIngredientsButton setTitle:@"" forState:UIControlStateNormal];
} else {
    missingIngredientsButton.selected = NO;
    [missingIngredientsButton setTitle:[NSString stringWithFormat:@"%u", missingIngredients.count] forState:UIControlStateNormal];
}

// make back view invisible.
UIView *backView = [cell viewWithTag:1];
UIView *frontView = [cell viewWithTag:5];
frontView.alpha = 1.0;
backView.alpha = 0;

// adding flip gesture recognizers
UIView *flipView1 = [cell viewWithTag:12];
UIView *flipView2 = [cell viewWithTag:1];

UITapGestureRecognizer *flipGestureRecognizer1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(flipCell:)];
UITapGestureRecognizer *flipGestureRecognizer2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(flipCell:)];
[flipView1 addGestureRecognizer:flipGestureRecognizer1];
[flipView2 addGestureRecognizer:flipGestureRecognizer2];

return cell;
}

[编辑]我附上了我的仪器运行的截图。 enter image description here

您可以看到内存分配增加,因为我只是按下segue并反复按下后退按钮。不断增加的是CFData,CALayer,CABackingStore,UITableView。我怀疑这些是在segue之后创建的东西,并且它们没有被释放......请帮忙!

2 个答案:

答案 0 :(得分:1)

您可能需要某种图像缓存策略以避免重新下载图像。 UIImageView+AFNetworking类别会为您缓存图像。但您也可能将响应缓存在内存中的URL缓存中,在这种情况下,这有点多余。

因此,您可以考虑减少或关闭内存中的URL缓存。我有你正在描述的问题,以下内容减少了我的记忆问题:

NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil];
[NSURLCache setSharedURLCache:sharedCache];

答案 1 :(得分:0)

AFNetworking会自动将图像存储在NSCache集合中,该集合会在低内存警告时自动从内存中删除部分或全部图像。 AFNetworking可能不是你的问题。

事实上,我不认为显示图像是你的问题,除非你下载大量非常大的图像并同时显示它们。 (如果是这种情况,您应该尝试优化图像以便在设备上显示,这样就不需要调整它们的大小。)

我看到的一个问题是,每次进入视图时,您都会向单元格添加手势识别器,但是单元格会被重复使用,因此当单元格再次进入时,您会向其中添加不必要的手势识别器。您可以通过继承UITableViewCell并将手势识别器指定为属性来解决此问题。您也可以通过检查flipView1flipView2来确定他们是否在添加手势识别器之前附加了手势识别器。 (我不确定这是否足以引起记忆警告。)

我建议去Build - >配置文件并选择分配工具。在左侧,仅选择Objective C,并隐藏系统调用。然后,滚动您的集合视图并查看仪器以查看占用所有内存的内容。

<强>更新

以下是分配工具的屏幕截图:

enter image description here