0

我目前正在处理带有很多图像的 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;
}

[编辑] 我附上了我的仪器运行的屏幕截图。 在此处输入图像描述

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

4

2 回答 2

1

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

因此,您可能会考虑减少或关闭内存中的 URL 缓存。我遇到了您所描述的问题,以下内容大大减少了我的记忆问题:

NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil];
[NSURLCache setSharedURLCache:sharedCache];
于 2013-06-08T21:48:54.113 回答
0

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

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

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

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

更新

这是分配工具的屏幕截图:

在此处输入图像描述

于 2013-06-08T21:07:21.213 回答