2

I'm displaying lot of images (5k images) in UICollectionView. These images has been download from remote server. When I scroll from top to bottom and vice versa of the UICollectionView for 5 to 6 times, my app get crashes and I received error "Terminating app due to memory pressure". Please advice to fix this issue.

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return urlLists.count;
}


- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
   UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"cellIdentifier" forIndexPath:indexPath];
    UIImageView *cellImage=[[UIImageView alloc]init];
    cellImage.frame=cell.contentView.bounds;

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:[urlLists objectAtIndex:indexPath.row]]];
        UIImage *image = [UIImage imageWithData:data];
        UIImageJPEGRepresentation(image, 0.1);
                data=nil;
         dispatch_async(dispatch_get_main_queue(), ^{
            cellImage.image=image;
        });
    });

    NSLog(@"The Indexpath=%ld", indexPath.row);
    [cell.contentView addSubview:cellImage];

    return cell;

}
Rob
  • 415,655
  • 72
  • 787
  • 1,044
BSS
  • 31
  • 8

2 Answers2

3

There are three levels of problem here:

  1. The most egregious problem is that you're adding a new UIImageView to the cell every time the cell is used. But cells can be reused many times, so you're adding many image views to the cell. The images associated with all of those other image views will take up memory.

    The easiest/best solution in my opinion is to use a cell prototype, add the image view there, and don't programmatically add image views. Alternatively, you can add the image view programmatically, but make sure you don't add new image views every time.

    By the way, do not be tempted (as will likely be suggested by others here) to turn off cell reuse by manually instantiating a new cell every time. Yes, it's an easy solution, but not an efficient one.

  2. A more subtle issue is that you're calling UIImageJPEGRepresentation in what I'm guessing is an attempt to reduce the memory involved. That does not do what you think it does. Yes, it creates a compressed JPEG representation, but you don't do anything with it. You're just discarding it.

    If you want to optimize memory and the images are high resolution, consider resizing the image to a size appropriate for the cell. See UIImage resizing not working properly for an example resizing category.

  3. Consider using UIImageView category of SDWebImage or AFNetworking, which does lazy loading and caching of images.

    This code in the question will not properly reset the image view before initiating the asynchronous retrieval. It will not handle the scenario if the cell is reused before the image retrieval is done. It may unnecessarily re-retrieve images that were downloaded a few seconds ago. Etc.

    There are lots of issues associated with gracefully retrieving images asynchronously, and the UIImageView categories of those two classes take care a lot of these details for you.

Community
  • 1
  • 1
Rob
  • 415,655
  • 72
  • 787
  • 1,044
1

Have you tried to Profile app and look where exactly it leaks?

Dima Cheverda
  • 402
  • 1
  • 4
  • 10