使用Photos框架请求照片时内存泄漏

时间:2014-11-05 10:52:24

标签: ios memory-leaks photosframework

我使用以下方法请求许多照片并将它们添加到数组中供以后使用:

-(void) fetchImages{

        self.assets = [[PHFetchResult alloc]init];
        PHFetchOptions *options = [[PHFetchOptions alloc] init];
        options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
        self.assets = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:options];

        self.photosToVideofy = [[NSMutableArray alloc]init];

        CGSize size = CGSizeMake(640, 480);
        PHImageRequestOptions *photoRequestOptions = [[PHImageRequestOptions alloc]init];
        photoRequestOptions.synchronous = YES;

        for (NSInteger i = self.firstPhotoIndex; i < self.lastPhotoIndex; i++)
        {
            PHAsset *asset = self.assets[i];
            [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:size contentMode:PHImageContentModeAspectFit options:photoRequestOptions resultHandler:^(UIImage *result, NSDictionary *info) {
                if (result) {
                    [self.photosToVideofy addObject:result];


                }
            }];
        }
        NSLog(@"There are %lu photos to Videofy", (unsigned long)self.photosToVideofy.count);

}

当照片数量少于50时,此功能正常。在内存跳转到150-160mb后,我收到消息Connection to assetsd was interrupted or assetsd died,应用程序崩溃。 在得到我想要的资产后,如何从内存中释放资产(PHFetchResult)?(我需要吗?) 我希望能够添加多达150张照片。 有任何想法吗? 感谢

4 个答案:

答案 0 :(得分:2)

您不应将PHFetchResult的结果放入数组中。 PHFetchResult的想法是指向照片库中的许多图像,而不是将它们全部存储在RAM中(我不确定它是如何做到的)只是像数组一样使用PHFetchResult对象,它处理内存问题您。例如,将collectionViewController直接连接到PHFetchResult对象,并使用PHImageManager仅为可见单元格等请求图像。

来自苹果文档: &#34;然而,与NSArray对象不同,PHFetchResult对象根据需要从Photos库动态加载其内容,即使在处理大量结果时也能提供最佳性能。&#34; https://developer.apple.com/library/ios/documentation/Photos/Reference/PHFetchResult_Class/

答案 1 :(得分:1)

你必须设置

photoRequestOptions.synchronous = NO;

而不是

photoRequestOptions.synchronous = YES;

为我工作,iOS 10.2

答案 2 :(得分:0)

你在fetchImages方法中的代码需要一些重构,看看这个建议:

-(void) fetchImages {

    PHFetchOptions *options = [[PHFetchOptions alloc] init];
    options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
    PHFetchResult *assets = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:options];

    self.photosToVideofy = [[NSMutableArray alloc] init];

    CGSize size = CGSizeMake(640, 480);
    PHImageRequestOptions *photoRequestOptions = [[PHImageRequestOptions alloc] init];
    photoRequestOptions.synchronous = YES;

    for (NSInteger i = self.firstPhotoIndex; i < self.lastPhotoIndex; i++)
    {
        PHAsset *asset = assets[i];
        [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:size contentMode:PHImageContentModeAspectFit options:photoRequestOptions resultHandler:^(UIImage *result, NSDictionary *info) {
            if (result) {
                [self.photosToVideofy addObject:result];


            }
        }];
    }
    NSLog(@"There are %lu photos to Videofy", (unsigned long)self.photosToVideofy.count);
}

但问题是内存消耗。让我们做一些计算。

单张图像,使用ARGB和每像素4个字节:

640x480x4 = 1.2MB

现在,您想要在RAM 150中存储图像,所以:

150x1.2MB = 180MB

例如,如果您使用大约300 MB的数据,那么512 MB的iPhone 4会崩溃,但如果其他应用程序也消耗大量RAM,则可能会减少。

我认为,您应该考虑将图像存储到文件而不是RAM。

答案 3 :(得分:0)

这可能是有意的(无法查看代码的其余部分),但是self.photosToVideofy永远不会发布:因为你在一个块中访问它,你传递的对象块([PHImageManager defaultManager])将始终具有对数组的引用。

在完成图像后,尝试明确清除阵列。阵列本身仍然不会被释放,但它包含的对象将会(或者如果它们没有在其他任何地方被引用)。

最好的解决方案是从块中删除数组。但是,这需要更改代码的逻辑。