【问题标题】:ios - Calculate total image size in photos folderios - 计算照片文件夹中的总图像大小
【发布时间】:2016-08-16 20:27:48
【问题描述】:

我正在尝试计算照片文件夹中图像的总存储空间。我编写了如下代码。我能够成功获取图像,但此代码有两个问题 -

  1. 如果照片有超过 7000 张图片,有时应用程序会崩溃。从,记录我 了解它的内存问题。

  2. 如果我多次来回运行此代码,在 6-7 次后应用程序会崩溃。

任何想法都会非常有帮助。我需要单独计算视频和歌曲的存储空间

-(void)getPhotoSize{

    dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [_allPhotos enumerateObjectsUsingBlock:^(PHAsset *asset, NSUInteger idx, BOOL *stop) {
            if (idx<_allPhotos.count&&asset) {

                [[PHImageManager defaultManager] requestImageDataForAsset:asset options:nil resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
                    float imageSize = imageData.length;
                    imageSize = imageSize;
                    data.totalPictureSize+=imageSize;
                      _currentPhotoAsset=asset;
                }];
            }
        }];
    });
}

【问题讨论】:

  • 你试过用 Instruments 运行看看是什么消耗了内存吗?
  • 是的,在来回操作时,我运行内存来检查泄漏。但无法找出确切的点

标签: ios objective-c storage objective-c-blocks


【解决方案1】:

我不明白您是在调度代码而不是仅仅运行它,所以我将从下面的示例中删除 GCD 部分。您还需要运行 Instruments 来检查泄漏并找出正在消耗内存的内容,但我的猜测是您通过直接访问 ivar 有一个隐式保留周期。试试这个:

-(void)getPhotoSize{
    for (PHAsset *asset in _allPhotos) {
        typeof(self) __weak weakSelf = self; // weak reference to self to avoid retain cycle
        [[PHImageManager defaultManager] requestImageDataForAsset:asset options:nil resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
            typeof(self) __strong strongSelf = weakSelf; // strong reference to make sure self exists until the block finishes

            float imageSize = imageData.length;
            imageSize = imageSize;
            strongSelf.data.totalPictureSize+=imageSize;
            strongSelf.currentPhotoAsset=asset;
        }];        
    }
}

我也将其更改为常规 for 循环以避免嵌套块。


快速而肮脏的异步版本

-(void)photoSizeWithCompletion:(void (^)(float))completion {
    NSArray *assets = _allPhotos;

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        float totalSize = 0;
        for (PHAsset *asset in assets) {
            [[PHImageManager defaultManager] requestImageDataForAsset:asset options:nil resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
                totalSize += imageData.length;
            }];        
        }            

        completion(totalSize);
    });
}

这样称呼它:

[someObject photoSizeWithCompletion:^(float totalSize){
    // use the totalSize
}]

这不支持当用户点击后退按钮时取消。但我会把它作为家庭作业来研究NSOperationQueue 以进行可取消的异步操作。查看 Apple 在 operation queues and concurrency 上的文档。

【讨论】:

  • 如果我不调度它会阻塞我的 UI。这就是为什么我试图在后台线程中运行它。
  • 但是如果你dispatch_sync 它仍然会阻塞你的调用者线程。你的意思是使用dispatch_async
  • 刚刚注意到data 似乎也是一个ivar,所以使用strongSelf.data 访问它并避免保留循环。
  • 是的,因为需要计算大量数据非常耗时。而且我不想阻止我的用户界面。大约需要 18-20 秒。压回去再回来让情况变得更糟。
  • 我已经用一个快速而肮脏的异步版本更新了答案。您应该阅读更多关于并发的信息,这并不像完成这个问题听起来那么简单。我觉得原始问题的答案就在那里。
猜你喜欢
  • 1970-01-01
  • 2011-08-17
  • 2018-10-10
  • 2011-01-12
  • 1970-01-01
  • 2018-10-10
  • 2019-01-06
相关资源
最近更新 更多