PhotoKit相册的性能优化

来源:互联网 发布:美工是什么职位类别 编辑:程序博客网 时间:2024/05/20 00:36

有关PhotoKit的基础知识,参考我的另一篇博文: 优雅的创建一个相册管理类。
这篇文章记录一下在实际项目中,自定义相册的优化工作。

之前的文章提到过,获取照片高清原图使用下面的方法:

    PHImageManager *manger = [PHImageManager defaultManager];    PHImageRequestOptions * options = [[PHImageRequestOptions alloc] init];    options.deliveryMode = PHImageRequestOptionsDeliveryModeFastFormat;    options.synchronous = YES;    options.resizeMode = PHImageRequestOptionsResizeModeFast;    options.networkAccessAllowed = NO;[manger requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {           //获取照片 result}];

在实际的使用过程中,如果涉及多张照片循环获取原图,就会出现内存大幅度上升的问题。通过Allcation就行内存检测的时候,发现正是该方法会占用很大的内存。

经过查找资料和自己的验证后,发现可以通过下面的方法获取图片。这样内存会稳定,就不会引起这样内存的问题。

    [manger requestImageDataForAsset:asset options:options resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {        UIImage *image = [UIImage imageWithData:imageData];        //获取照片 image    }];

该方法是获取先图片的二进制流,然后转化为UImage。


另外,对于滑动相册的时候,内存也会出现一定的增大,虽然不会造成明显的卡顿现象。
但官方也给出了PhotoKit的缓存机制接口,更好的优化内存,提升滑动的流畅性。

具体方法如下:

在当前拥有UICollectionView的视图控制器中:

@property (nonatomic, assign) CGRect previousPreheatRect;@property (nonatomic, strong) PHCachingImageManager *imageManager;
- (PHCachingImageManager *)imageManager{    if (_imageManager == nil) {        _imageManager = [PHCachingImageManager new];    }    return _imageManager;}- (void)viewDidAppear:(BOOL)animated{    [super viewDidAppear:animated];    [self updateCachedAssets];}- (void)scrollViewDidScroll:(UIScrollView *)scrollView{    [self updateCachedAssets];}

该缓存方案的原理就是缓存frame范围内所对应的显示到cell上的照片的PHAsset对象。这样在滑动的时候直接读取缓存里面的数据,避免了反复根据index去给cell赋值的操作。

- (void)updateCachedAssets{    BOOL isViewVisible = [self isViewLoaded] && self.view.window != nil;    if (!isViewVisible) { return; }    // The preheat window is twice the height of the visible rect    CGRect preheatRect = self.collectionView.bounds;    preheatRect = CGRectInset(preheatRect, 0.0, -0.5 * CGRectGetHeight(preheatRect));    // If scrolled by a "reasonable" amount...    CGFloat delta = ABS(CGRectGetMidY(preheatRect) - CGRectGetMidY(self.previousPreheatRect));    if (delta > CGRectGetHeight(self.collectionView.bounds) / 3.0) {        // Compute the assets to start caching and to stop caching        NSMutableArray *addedIndexPaths = [NSMutableArray array];        NSMutableArray *removedIndexPaths = [NSMutableArray array];        [self computeDifferenceBetweenRect:self.previousPreheatRect andRect:preheatRect addedHandler:^(CGRect addedRect) {            NSArray *indexPaths = [self apple_indexPathsForElementsInRect:addedRect];            [addedIndexPaths addObjectsFromArray:indexPaths];        } removedHandler:^(CGRect removedRect) {            NSArray *indexPaths = [self apple_indexPathsForElementsInRect:removedRect];            [removedIndexPaths addObjectsFromArray:indexPaths];        }];        NSArray *assetsToStartCaching = [self assetsAtIndexPaths:addedIndexPaths];        NSArray *assetsToStopCaching = [self assetsAtIndexPaths:removedIndexPaths];        CGSize itemSize = CGSizeMake((ScreenWidth-15)/3, (ScreenWidth-15)/3);        CGSize targetSize = CGSizeScale(itemSize, self.traitCollection.displayScale);        [self.imageManager startCachingImagesForAssets:assetsToStartCaching                                            targetSize:targetSize                                           contentMode:PHImageContentModeAspectFill                                               options:nil];        [self.imageManager stopCachingImagesForAssets:assetsToStopCaching                                           targetSize:targetSize                                          contentMode:PHImageContentModeAspectFill                                              options:nil];        self.previousPreheatRect = preheatRect;    }}
- (void)computeDifferenceBetweenRect:(CGRect)oldRect andRect:(CGRect)newRect addedHandler:(void (^)(CGRect addedRect))addedHandler removedHandler:(void (^)(CGRect removedRect))removedHandler{    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 *)apple_indexPathsForElementsInRect:(CGRect)rect{    NSArray *allLayoutAttributes = [self.collectionView.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;}
- (NSArray *)assetsAtIndexPaths:(NSArray *)indexPaths{    if (indexPaths.count == 0) { return nil; }    NSMutableArray *assets = [NSMutableArray arrayWithCapacity:indexPaths.count];    for (NSIndexPath *indexPath in indexPaths) {        if (indexPath.item < self.fetchResult.count && indexPath.item != 0) {            PHAsset *asset = self.fetchResult[self.fetchResult.count-indexPath.item];            [assets addObject:asset];        }    }    return assets;}

END.

0 0
原创粉丝点击