【问题标题】:memory leak when requesting photos using the Photos framework使用 Photos 框架请求照片时内存泄漏
【发布时间】:2014-11-05 10:52:23
【问题描述】:

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

-(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 张照片。 有任何想法吗? 谢谢

【问题讨论】:

    标签: ios memory-leaks photosframework


    【解决方案1】:

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

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

    【讨论】:

    • 要获取照片,我同意您不需要使用资源数组,但是当需要实际请求图像时,您必须将它们存储在某个地方...
    【解决方案2】:

    您的 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。

    【讨论】:

    • 感谢您的回复。
    • “您应该考虑将图像存储到文件而不是 RAM”。那句话对我帮助很大。事实上,在请求视频时,我们得到的是视频的 URL,而不是视频本身;并且不会发生内存问题。所以我会对图像做同样的事情:请求图像,然后立即将它们存储到磁盘的缓存目录中,并将 URL 传递给需要访问图像的任何人。
    【解决方案3】:

    这可能是故意的(如果不查看您的其余代码就无法判断),但 self.photosToVideofy 永远不会被释放:因为您是在一个块中访问它,所以您将块传递给的对象([ PHImageManager defaultManager]) 将始终具有对数组的引用。

    当您处理完图像后,请尝试明确清除您的数组。数组本身仍然不会被释放,但它包含的对象将(或者如果它们没有在其他任何地方引用,则可以)。

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

    【讨论】:

    • 嗨安娜!我看到了你的答案。我想这与保留/循环之类的事情有关?我想问一下在 Swift 中,这是否也相关?如果是这样,会调用myArrayOfWhatEver = nil,应该清除内存吗?谢谢!
    【解决方案4】:

    你必须设置

    photoRequestOptions.synchronous = NO;
    

    而不是

    photoRequestOptions.synchronous = YES;
    

    为我工作,iOS 10.2

    【讨论】:

    • 这与请求的照片的存储方式无关。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-05
    • 2011-01-05
    • 2011-05-29
    相关资源
    最近更新 更多