神刀安全网

PhotoKit制作相册或选择器(四):预加载策略

前言

上一篇文章里我们已经将图片选择器的基本功能完成了。相册里图片比较多的小伙伴有没有觉得上下滚动起来不是很顺呢(当然,像小编这种屌丝挫男可能不会有这烦恼,相册空空如也,没有自拍就没有噩梦),那怎么来处理这种同时请求巨巨巨巨巨多图片的情况呢,这里Apple API里给我们指了条路(蹩脚英文得派上场了LOOOOOOOOOOL

PhotoKit制作相册或选择器(四):预加载策略

如果需要同时加载多个资源的图片数据,使用PHCachingImageManager类通过加载你马上想要的图片来“预加载”缓存。打个比方,在一个显示图片资源缩略图的collection view内,你可以在滚动到当前位置前就缓存好图片。

PhotoKit制作相册或选择器(四):预加载策略

使用这些类来请求有关Photos资源的图片,视频,活图内容。
Photos框架根据你的要求自动下载并生成图片,缓存它们,为了更快的复用。为了大量资源能更快地表现,你也可以批请求预加载图片。

那现在的思路就是在UICollectionView滚动前,先缓存可能显示的图片,也就是当前可显示区域前后将要显示的图片。

开始

定义所需属性

//缓存图片管理器 @property (nonatomic, strong) PHCachingImageManager *imageManager; //先前预加载区域,用于比较 @property CGRect previousPreheatRect;

更新缓存

  1. 判断界面是否显示
  2. 初始化预加载区域大小,在可显示区域基础上前后各增加个可显示区域
  3. 当滚动范围大于当前显示界面的三分之一时,进行缓存操作(由于此方法会在scrollview的代理方法scrollViewDidScroll:中调用,频繁调用会影响性能,这里的规则可以根据需求进行调控)
  4. 区别新增资源以及移除资源,进行缓存更新
- (void)updateCachedAssets {     BOOL isViewVisible = [self isViewLoaded] && [[self view] window] != nil;     if (!isViewVisible) { return; }      // 预加载区域是可显示区域的两倍     CGRect preheatRect = self.collectionView.bounds;     preheatRect = CGRectInset(preheatRect, 0.0f, -0.5f * CGRectGetHeight(preheatRect));      //     比较是否显示的区域与之前预加载的区域有不同     CGFloat delta = ABS(CGRectGetMidY(preheatRect) - CGRectGetMidY(self.previousPreheatRect));     if (delta > CGRectGetHeight(self.collectionView.bounds) / 3.0f) {          // 区分资源分别操作         NSMutableArray *addedIndexPaths = [NSMutableArray array];         NSMutableArray *removedIndexPaths = [NSMutableArray array];          [self computeDifferenceBetweenRect:self.previousPreheatRect andRect:preheatRect removedHandler:^(CGRect removedRect) {             NSArray *indexPaths = [self indexPathsForElementsInCollectionView:self.collectionView rect:removedRect];             [removedIndexPaths addObjectsFromArray:indexPaths];         } addedHandler:^(CGRect addedRect) {             NSArray *indexPaths = [self indexPathsForElementsInCollectionView:self.collectionView rect:addedRect];             [addedIndexPaths addObjectsFromArray:indexPaths];         }];          NSArray *assetsToStartCaching = [self assetsAtIndexPaths:addedIndexPaths];         NSArray *assetsToStopCaching = [self assetsAtIndexPaths:removedIndexPaths];          // 更新缓存         [self.imageManager startCachingImagesForAssets:assetsToStartCaching                                             targetSize:AssetGridThumbnailSize                                            contentMode:PHImageContentModeAspectFill                                                options:nil];         [self.imageManager stopCachingImagesForAssets:assetsToStopCaching                                            targetSize:AssetGridThumbnailSize                                           contentMode:PHImageContentModeAspectFill                                               options:nil];          // 存储预加载矩形已供比较         self.previousPreheatRect = preheatRect;     } }
  • 此方法是区分增加的区域以及减少的区域
- (void)computeDifferenceBetweenRect:(CGRect)oldRect andRect:(CGRect)newRect removedHandler:(void (^)(CGRect removedRect))removedHandler addedHandler:(void (^)(CGRect addedRect))addedHandler {     if (CGRectIntersectsRect(newRect, oldRect)) {         CGFloat oldMaxY = CGRectGetMaxY(oldRect);         CGFloat oldMinY = CGRectGetMinY(oldRect);         CGFloat newMaxY = CGRectGetMaxY(newRect);         CGFloat newMinY = CGRectGetMinY(newRect);          if (newMaxY > oldMaxY) {             CGRect rectToAdd = CGRectMake(newRect.origin.x, oldMaxY, newRect.size.width, (newMaxY - oldMaxY));             addedHandler(rectToAdd);         }          if (oldMinY > newMinY) {             CGRect rectToAdd = CGRectMake(newRect.origin.x, newMinY, newRect.size.width, (oldMinY - newMinY));             addedHandler(rectToAdd);         }          if (newMaxY < oldMaxY) {             CGRect rectToRemove = CGRectMake(newRect.origin.x, newMaxY, newRect.size.width, (oldMaxY - newMaxY));             removedHandler(rectToRemove);         }          if (oldMinY < newMinY) {             CGRect rectToRemove = CGRectMake(newRect.origin.x, oldMinY, newRect.size.width, (newMinY - oldMinY));             removedHandler(rectToRemove);         }     } else {         addedHandler(newRect);         removedHandler(oldRect);     } }  - (NSArray *)assetsAtIndexPaths:(NSArray *)indexPaths {     if (indexPaths.count == 0) { return nil; }      NSMutableArray *assets = [NSMutableArray arrayWithCapacity:indexPaths.count];     for (NSIndexPath *indexPath in indexPaths) {         PHAsset *asset = self.assetsFetchResults[indexPath.item];         [assets addObject:asset];     }      return assets; }
  • 此方法作用是获取某区域内元素的indexPaths
- (NSArray *)indexPathsForElementsInCollectionView:(UICollectionView *)collection rect:(CGRect)rect {     NSArray *allLayoutAttributes = [collection.collectionViewLayout layoutAttributesForElementsInRect:rect];     if (allLayoutAttributes.count == 0) { return nil; }     NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:allLayoutAttributes.count];     for (UICollectionViewLayoutAttributes *layoutAttributes in allLayoutAttributes) {         NSIndexPath *indexPath = layoutAttributes.indexPath;         [indexPaths addObject:indexPath];     }     return indexPaths; }
  • 界面显示时需第一次更新缓存
- (void)viewDidAppear:(BOOL)animated {     [super viewDidAppear:animated];      // 可见区域刷新缓存     [self updateCachedAssets]; }
  • UICollectionView滚动时更新缓存
#pragma mark -- UIScrollViewDelegate  - (void)scrollViewDidScroll:(UIScrollView *)scrollView {     [self updateCachedAssets]; }

上一篇我们实现了相册变化的检测,那么如果相册资源变化了,缓存如何操作呢?
这里小编直接将缓存重置,简单粗暴~

- (void)resetCachedAssets {     [self.imageManager stopCachingImagesForAllAssets];     self.previousPreheatRect = CGRectZero; }

是不是觉得已经大功告成了?其实还有个很重要的地方要改,不然就白忙活了!
-collectionView:collectionView cellForItemAtIndexPath:这个代理方法内,我们请求图片使用的[PHImageManager defaultManager]换成self.imageManager。因为我们使用的是此对象来进行一系列缓存操作的。

附上DEMO

结束语

这个简单的选择器功能还不够完善,主要是熟悉Photos框架,如果读者感兴趣的话,可以持续关注小编的ASImagePicker

ASImagePicker持续更新中…
https://github.com/alanshen0118/ASImagePicker

文章中有任何错误希望读者能积极指出,我会及时更正。
如果喜欢,请持续关注,顺便点个喜欢噢👇👇👇帮五菱加加油~@_@

Thanks!!!

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » PhotoKit制作相册或选择器(四):预加载策略

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址