简体   繁体   English

从带有元数据的照片库中获取图像时出现内存问题

[英]Memory issue while fetching images from Photos library with metadata

I'm trying to get all photos from photos library with image's metadata. 我正在尝试从照片库中获取包含图像元数据的所有照片。 It works fine for 10-20 images but when there are 50+ images it occupies too much memory, which causes to app crash. 它适用于10到20张图像,但是当有50张以上图像时,它占用过多的内存,这会导致应用崩溃。

Why i need all images into array? 为什么我需要将所有图像排列成阵列?
Answer - to send images to server app. 答案 -将图像发送到服务器应用程序。 [i'm using GCDAsyncSocket to send data on receiver socket/port and i don't have that much waiting time to request images from PHAsset while sending images on socket/port. [我正在使用GCDAsyncSocket在接收器套接字/端口上发送数据,而在套接字/端口上发送图像时,我没有那么多的等待时间来从PHAsset请求图像。

My Code : 我的代码:

+(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;

}

Well it's not a surprise that you arrive into this situation, since each of your image consumes memory and you instantiate and keep them in memory. 好吧,遇到这种情况并不奇怪,因为每个图像都占用内存,并且您实例化并将它们保留在内存中。 This is not really a correct design approach. 这实际上不是正确的设计方法。 In the end it depends on what you want to do with those images. 最后,这取决于您要对这些图像执行的操作。

What I would suggest is that you keep just the array of your PHAsset objects and request the image only on demand. 我的建议是,仅保留PHAsset对象的数组,仅按需请求图像。 Like if you want to represent those images into a tableView/collectionView, perform the call to 就像您想将这些图像表示为tableView / collectionView一样,执行对

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

directly in the particular method. 直接使用特定方法。 This way you won't drain the device memory. 这样,您就不会耗尽设备内存。

There simply is not enough memory on the phone to load all of the images into the photo library into memory at the same time. 手机上没有足够的内存来同时将所有图像加载到照片库到内存中。

If you want to display the images, then only fetch the images that you need for immediate display. 如果要显示图像,则仅获取立即显示所需的图像。 For the rest keep just he PHAsset . 对于其余的,只保留他PHAsset Make sure to discard the images when you don't need them any more. 确保不再需要图像时将其丢弃。

If you need thumbnails, then fetch only the thumbnails that you need. 如果需要缩略图,则仅获取所需的缩略图。

If want to do something with all of the images - like add a watermark to them or process them in some way - then process each image one at a time in a queue. 如果要对所有图像进行处理(例如向它们添加水印或以某种方式处理它们),则在队列中一次处理一个图像。

I cannot advise further as your question doesn't state why you need all of the images. 我无法提供进一步的建议,因为您的问题并未说明为什么需要所有图像。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从照片 SwiftUI 获取图像时用完 memory - Running out of memory while fetching images from Photos SwiftUI 从设备照片库中获取图像时出现内存警告 - Memory Warning on fetching images from device photo library 来自调试器的消息:由于内存问题而终止在 UITableView/UICollectionView 中滚动时使用 gif 图像 Kingfisher Library - Message from debugger: Terminated due to memory issue While scrolling in UITableView/UICollectionView with gif images Kingfisher Library 基于 iOS 中的元数据从照片库中加载/检索图像 - Loading/Retrieving an image from Photos Library based on metadata in iOS 从照片库加载图像并按日期排序时出现内存问题 - Memory issue on Loading images from Photo Library and sort them datewise 绘制单元格时从服务器获取图像 - Fetching images from server while drawing the cell 在iOS中通过HTTP获取图像时不断增长的内存分配 - Constantly growing memory allocation while fetching images over HTTP in iOS 从ios中的照片库检索照片时内存泄漏 - Memory leaks when Retrieving photos from Photo Library in ios 将多个图像上传到服务器时出现内存问题 - Memory issue while uploading multiple images to server 动画许多图像时出现内存问题 - Memory issue while Animating many images
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM