Karuppu MGR Karuppu MGR - 6 months ago 125
Objective-C Question

Collection view images are flickering while scrolling

Im using the following code to populate a collection view cells with images.

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = @"Cell";

UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];

UIImageView *recipeImageView = (UIImageView *)[cell viewWithTag:100];
recipeImageView.image = nil;
if ([imageArray count] >0){

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void) {
NSData *data0 = [NSData dataWithContentsOfURL: [NSURL URLWithString:[imageArray objectAtIndex:indexPath.row]]];
UIImage *image = [UIImage imageWithData: data0];

dispatch_sync(dispatch_get_main_queue(), ^(void) {
recipeImageView.image = image;
});
});

}

[spinnerShow stopAnimating];


return cell;
}


The problem is that, when Im scrolling the images are flickering and are flashing. Why is that so? How can I make those images to be stable without flickering?

Answer

Just a short overview, So you get your answer

UICollectionView is highly optimized, and thus only keep On-screen visible rows in memory. Now, All rows Cells are cached in Pool and are reused and not regenerated. Whenever, user scrolls the UICollectionView, it adds the just-hidden rows in Pool and reuses them for next to be visible rows.

So, now, coming to your answer

When you scroll your CollectionView, collectionView datasource method gets called again for every indexPath, coming in visible range and your image gets downloaded again

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath

SOLUTION

Instantiate a instance NSMutableDictionary, outside of method.

Now in your code

@implementation ClassName{
  NSMutableDictionary *cachedImage;
}

-(void)viewDidLoad(){
  [super viewDidLoad];
  cachedImage = [NSMutableDictionary new];
}

/*OLD CODE*/
UIImageView *recipeImageView = (UIImageView *)[cell viewWithTag:100];
    recipeImageView.image = nil;

    if ([imageArray count] >0){
    //IF image is already downloaded, simply use it and don't download it.
       if(cachedImage[[imageArray objectAtIndex:indexPath.row]] != nil){
     recipeImageView.image = cachedImage[[imageArray objectAtIndex:indexPath.row]];
}
else{

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void) {
            NSData *data0 = [NSData dataWithContentsOfURL: [NSURL URLWithString:[imageArray objectAtIndex:indexPath.row]]];
            UIImage *image = [UIImage imageWithData: data0];

            dispatch_sync(dispatch_get_main_queue(), ^(void) {
                recipeImageView.image = image;
                //****SAVE YOUR DOWNLOADED IMAGE 
                cachedImage[[imageArray objectAtIndex:indexPath.row]] = image; //****SAVE YOUR DOWNLOADED IMAGE 
            });
        });
}


    }


/*OLD CODE*/