使用元数据从Photos库中获取图像时出现内存问题

时间:2017-07-20 06:41:54

标签: ios objective-c iphone

我试图通过图片的元数据从照片库中获取所有照片。它适用于10-20个图像,但是当有50个以上的图像时,它会占用太多内存,导致应用程序崩溃。

为什么我需要将所有图像放入阵列?
回答 - 将图像发送到服务器应用。 [我使用GCDAsyncSocket在接收器插槽/端口上发送数据,并且在插槽/端口上发送图像时,我没有那么多等待时间从PHAsset请求图像。

我的代码:

+(void)getPhotosDataFromCamera:(void(^)(NSMutableArray *arrImageData))completionHandler
{
    [PhotosManager checkPhotosPermission:^(bool granted)
    {
        if (granted)
        {
            NSMutableArray *arrImageData = [NSMutableArray new];

        NSArray *arrImages=[[NSArray alloc] init];

        PHFetchResult *result = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil];

        NSLog(@"%d",(int)result.count);

        arrImages = [result copy];

        //--- If no images.
        if (arrImages.count <= 0)
        {
            completionHandler(nil);
            return ;
        }

        __block int index = 1;
        __block BOOL isDone = false;
        for (PHAsset *asset in arrImages)
        {
            [PhotosManager requestMetadata:asset withCompletionBlock:^(UIImage *image, NSDictionary *metadata)
             {
                 @autoreleasepool
                 {
                     NSData *imageData = metadata?[PhotosManager addExif:image metaData:metadata]:UIImageJPEGRepresentation(image, 1.0f);

                     if (imageData != nil)
                     {
                         [arrImageData addObject:imageData];
                         NSLog(@"Adding images :%i",index);

                         //--- Done adding all images.
                         if (index == arrImages.count)
                         {
                             isDone = true;
                             NSLog(@"Done adding all images with info!!");
                             completionHandler(arrImageData);
                         }
                         index++;
                     }
                 }
             }];
        }
    }
    else
    {
        completionHandler(nil);
    }
}];
}


typedef void (^PHAssetMetadataBlock)(UIImage *image,NSDictionary *metadata);

+(void)requestMetadata:(PHAsset *)asset withCompletionBlock:(PHAssetMetadataBlock)completionBlock
{
    PHContentEditingInputRequestOptions *editOptions = [[PHContentEditingInputRequestOptions alloc]init];
    editOptions.networkAccessAllowed = YES;
    [asset requestContentEditingInputWithOptions:editOptions completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info)
     {
         CIImage *CGimage = [CIImage imageWithContentsOfURL:contentEditingInput.fullSizeImageURL];
         UIImage *image = contentEditingInput.displaySizeImage;

         dispatch_async(dispatch_get_main_queue(), ^{
             completionBlock(image,CGimage.properties);
         });

         CGimage = nil;
         image = nil;

     }];

    editOptions = nil;
    asset =nil;
}

+ (NSData *)addExif:(UIImage*)toImage metaData:(NSDictionary *)container
{



 NSData *imageData = UIImageJPEGRepresentation(toImage, 1.0f);
       // create an imagesourceref
    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef) imageData, NULL);

// this is the type of image (e.g., public.jpeg)
CFStringRef UTI = CGImageSourceGetType(source);

// create a new data object and write the new image into it
NSMutableData *dest_data = [[NSMutableData alloc] initWithLength:imageData.length+2000];
CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)dest_data, UTI, 1, NULL);

if (!destination) {
    NSLog(@"Error: Could not create image destination");
}

// add the image contained in the image source to the destination, overidding the old metadata with our modified metadata
CGImageDestinationAddImageFromSource(destination, source, 0, (__bridge CFDictionaryRef) container);
BOOL success = NO;
success = CGImageDestinationFinalize(destination);

if (!success) {
    NSLog(@"Error: Could not create data from image destination");
}

CFRelease(destination);
CFRelease(source);
imageData = nil;
source = nil;
destination = nil;

return dest_data;

}

2 个答案:

答案 0 :(得分:1)

你遇到这种情况并不奇怪,因为你的每个图像消耗内存并实例化并将它们保存在内存中。这不是一个真正的设计方法。 最后,这取决于你想对这些图像做些什么。

我建议您只保留PHAsset个对象的数组,并仅按需请求图像。 就像你想将这些图像表示到tableView / collectionView中一样,执行对

的调用

[PhotosManager requestMetadata:asset withCompletionBlock:^(UIImage *image, NSDictionary *metadata)

直接在特定方法中。这样你就不会耗尽设备内存。

答案 1 :(得分:0)

手机上没有足够的内存可以同时将所有图像加载到照片库中。

如果要显示图像,则只获取立即显示所需的图像。其余的只留下他PHAsset。当你不再需要它们时,请务必丢弃图像。

如果您需要缩略图,请仅提取您需要的缩略图。

如果想对所有图像执行某些操作(例如为其添加水印或以某种方式处理它们),则在队列中一次处理一个图像。

我无法进一步提出建议,因为您的问题并未说明为什么您需要所有图片。