Preloading the next (currently invisible) UICollectionView cell

I am working with a UICollectionView and currently have full screen cells and when I sit in the next cell the image takes a bit to load into the cell (since they are high resolution). I already use PHCachingImageManager to cache the image before hand and it is already cached before loading the cell, but just loading the image into the ImageView takes a noticeable spark of time. I was wondering if there is a way to preload the invisible next cell before it hits cellForItemAtIndexPath?

Any thoughts?

+3


source to share


1 answer


Apparently it takes a while to load an image that was already cached from PHCachingImageManager which caused my delay. I created a test function that saved the next image (and will add the previous one too) to a property when setting the current cell, and my flicker will no longer be there. I will output a working example when I cleaned it up ...

Update: So I created _images NSMutableDictionary to store the already loaded images and fill it with this function

- (void)startCachingSurroundingImages:(NSInteger)index {
CGSize targetSize = PHImageManagerMaximumSize;
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
[options setNetworkAccessAllowed:YES];
[options setDeliveryMode:PHImageRequestOptionsDeliveryModeHighQualityFormat];

if (index < _imagesArray.count - 1 && ![_images objectForKey:[NSIndexPath indexPathForItem:0 inSection:index+1]]) {
    NSDictionary *assetDictionary = [_imagesArray objectAtIndex:index + 1];
    NSString *assetRefID = [assetDictionary objectForKey:@"asset_id"];

    PHFetchResult *assetFetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[assetRefID] options:[PHFetchOptions new]];
    PHAsset *asset = [assetFetchResult firstObject];



    [photoManager requestImageForAsset:asset targetSize:targetSize contentMode:PHImageContentModeAspectFit options:options resultHandler:^(UIImage *result, NSDictionary *info) {
        if (result) {
            [_images setObject:result forKey:[NSIndexPath indexPathForItem:0 inSection:index+1]];
        }
    }];
}

if (index - 1 >= 0 && ![_images objectForKey:[NSIndexPath indexPathForItem:0 inSection:index-1]]) {
    NSDictionary *leftAssetDictionary = [_imagesArray objectAtIndex:index - 1];
    NSString *leftAssetRefID = [leftAssetDictionary objectForKey:@"asset_id"];

    PHFetchResult *leftAssetFetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[leftAssetRefID] options:[PHFetchOptions new]];
    PHAsset *leftAsset = [leftAssetFetchResult firstObject];

    [photoManager requestImageForAsset:leftAsset targetSize:targetSize contentMode:PHImageContentModeAspectFit options:options resultHandler:^(UIImage *result, NSDictionary *info) {
        if (result) {
            [_images setObject:result forKey:[NSIndexPath indexPathForItem:0 inSection:index-1]];
        }
    }];
  }
}

      

Which I call on cellForItemAtIndexPath like this ...

[self startCachingSurroundingImages:indexPath.section];

      



and still in cellForItemAtIndexPath, I load the image like so ...

if ([_images objectForKey:indexPath]) {
    cell.imageView.image = [_images objectForKey:indexPath];
    [photoCell.activityIndicator setHidden:YES];
} else {
    photoCell.tag = (int)[photoManager requestImageForAsset:asset targetSize:targetSize contentMode:PHImageContentModeAspectFit options:options resultHandler:^(UIImage *result, NSDictionary *info) {
        PhotoCell *photoCell = (PhotoCell *)[self.collectionView cellForItemAtIndexPath:indexPath];
        if (photoCell && result) {
            photoCell.imageView.image = result;
            [photoCell.activityIndicator setHidden:YES];
        } else {
            NSLog(@"BAD IMAGE!!! %@", info);
            [photoCell.activityIndicator setHidden:NO];
        }
    }];
}

      

Then in didReceiveMemoryWarning I tidy up a bit ...

- (void)didReceiveMemoryWarning {
  NSArray *allKeys = [_images allKeys];
  for (int i = 0; i < _images.count; i++) {
    NSIndexPath *path = [allKeys objectAtIndex:i];
    if (path.section != _lastIndex && path.section != _lastIndex - 1 && path.section != _lastIndex + 1) {
        [_images removeObjectForKey:path];
    }
  }
  // Though one could just as easily do this 
  // [_images removeAllObjects];
}

      

It's not pretty, but it works.

+1


source







All Articles