如何使用 PhotoKit 减少内存使用?

Posted

技术标签:

【中文标题】如何使用 PhotoKit 减少内存使用?【英文标题】:How to reduce memory use with PhotoKit? 【发布时间】:2015-09-07 03:06:35 【问题描述】:

我正在使用PhotoKit 从系统相册中获取照片并将它们放入UICollectionView

    对于UICollectionViewCell,我是这样设置的:

    cell.imageView.contentMode = UIViewContentModeScaleAspectFill;
    

    初始化我的UICollectionView 时,我从collection 获取照片PHAsset:仅限Camera Roll

    PHFetchResult *fetchResult = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
    [fetchResult enumerateObjectsUsingBlock:^(PHAssetCollection *collection, NSUInteger idx, BOOL *stop) 
        NSLog(@"ALBUM NAME: %@", collection.localizedTitle);
        if ([collection.localizedTitle isEqualToString:@"Camera Roll"]) 
            _fetchedPhotos = [PHAsset fetchAssetsInAssetCollection:collection options:nil];
            _pickedStatuses = @[].mutableCopy;            
    
            NSMutableArray *assets = @[].mutableCopy;
    
            _manager = [[PHCachingImageManager alloc] init];
            _options = [[PHImageRequestOptions alloc] init];
            _options.resizeMode = PHImageRequestOptionsResizeModeExact;
            _options.deliveryMode = PHImageRequestOptionsDeliveryModeOpportunistic;
    
            CGFloat scale = [UIScreen mainScreen].scale;
            CGSize targetSize = CGSizeMake(layout.itemSize.width*scale, layout.itemSize.height*scale);
    
            //I'm not sure if this api should be called here
            [_manager startCachingImagesForAssets:assets targetSize:targetSize contentMode:PHImageContentModeAspectFill options:_options];
        
    ];
    

    然后我从上面的PHFetchResult 请求UIImage,如下所示:

    -(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
    
        MYCell *cell = (MYCell *)[collectionView dequeueReusableCellWithReuseIdentifier:@"reuseCell" forIndexPath:indexPath];
    
        CGFloat scale = [UIScreen mainScreen].scale;
        CGSize targetSize = CGSizeMake(_layout.itemSize.width*scale, _layout.itemSize.height*scale);
    
        PHAsset *asset = _fetchedPhotos[indexPath.item];
        [_manager requestImageForAsset:asset targetSize:targetSize contentMode:PHImageContentModeAspectFill options:_options resultHandler:^(UIImage *result, NSDictionary *info) 
             cell.imageView.image = result;
        ];
    
        return cell;
    
    

但是当我运行它并足够快地滚动UICollectionView时,我发现内存使用变得像这样急剧:

如果内存不足会崩溃,如何减少它?

【问题讨论】:

我期待这种模式,因为在 PhotoKit 可以创建缩略图之前,它必须将整个图像加载到内存中。另外,您是在设备上还是在模拟器中进行测试?两者之间的内存行为会有很大不同,因此请始终在设备上进行测试,以了解您的应用性能的真实情况。 我总是在我的 iPhone 6 Plus 设备上测试它。 【参考方案1】:

我现在做的是

    减少获取的PHAsset对象的目标大小;

    尝试采用缓存。我的代码如下:

    CGFloat scale = 1.5; //or an even smaller one
    if (!_manager) 
        _manager = [[PHCachingImageManager alloc] init];
    
    if (!_options) 
        _options = [[PHImageRequestOptions alloc] init];
    
    _options.resizeMode = PHImageRequestOptionsResizeModeExact;
    _options.deliveryMode = PHImageRequestOptionsDeliveryModeOpportunistic;
    
    NSRange range = NSMakeRange(0, _fetchedPhotos.count);
    NSIndexSet *set = [NSIndexSet indexSetWithIndexesInRange:range];
    NSArray *assets = [_fetchedPhotos objectsAtIndexes:set];
    
    CGSize targetSize = CGSizeMake(_layout.itemSize.width*scale, _layout.itemSize.height*scale);
    
    [_manager startCachingImagesForAssets:assets targetSize:targetSize contentMode:PHImageContentModeAspectFill options:_options];
    

现在即使我滚动UICollectionView 的速度足够快,顶部内存也将小于50 MB,并且感谢Caching(我猜它是基于我的代码工作的)它不会波动太大,内存使用是这样的:

更新 根据另一个帖子here,建议不要指定PHImageRequestOptions对象。相反,您可以让 ios 来决定哪种方式最适合您以最好的质量和最少的时间呈现照片。

【讨论】:

【参考方案2】:

我建议查看我提到的答案here。这不仅可以帮助您进行缓存,而且苹果的照片框架示例也可以帮助您解决任何问题。

【讨论】:

以上是关于如何使用 PhotoKit 减少内存使用?的主要内容,如果未能解决你的问题,请参考以下文章

如何解决 PhotoKit 错误“原始资源选择仅对未调整的基础版本有效”?

使用 PhotoKit 在文件夹内创建子文件夹

PhotoKit iOS8 - 使用“PHImageFileURLKey”检索图像

如何使用 Photo Kit 获取专辑海报图片?

如何减少 Cobalt 的内存使用量

iOS PhotoKit框架如何获取视频文件大小