Memory Warning on fetching images from device photo library

1.2k views Asked by At

I have used following code to fetch images from photo library, resizing it before displaying it is receiving memory warnings. Also it gets terminated due to memory pressure.

-(void)readImages:(int)getAlbumImages
{

    imagesArray = [[NSMutableArray alloc]init];
    allImagesArray = [[NSMutableArray alloc] init];

    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
    void (^assetEnumerator)( ALAsset *, NSUInteger, BOOL *) = ^(ALAsset *result, NSUInteger index, BOOL *stop) {
        if(result != nil) {
             if([[result valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypePhoto]) {
                        [allImagesArray addObject:[result valueForProperty:ALAssetPropertyURLs]];

                        NSURL *url= (NSURL*) [[result defaultRepresentation]url];
                        [library assetForURL:url
                                 resultBlock:^(ALAsset *asset) {
                                     [imagesArray addObject:[UIImage imageWithCGImage:[[asset defaultRepresentation] fullScreenImage]]];
                                     [picsTbl reloadData];
                                     [loadingView setHidden:YES];
                                 }
                                failureBlock:^(NSError *error){ NSLog(@"test:Fail"); } ];
                    }

                }
                else if(result == NULL){
                    [loadingView setHidden:YES];
                }
            };

            NSMutableArray *assetGroups = [[NSMutableArray alloc] init];
            void (^ assetGroupEnumerator) ( ALAssetsGroup *, BOOL *)= ^(ALAssetsGroup *group, BOOL *stop) {
                if(group != nil) {
                    [group enumerateAssetsUsingBlock:assetEnumerator];
                    [assetGroups addObject:group];
                    NSLog(@"Number of assets in group :%ld",(long)[group numberOfAssets]);
                    NSLog(@"asset group is:%@",assetGroups);
                }
                NSLog(@"[group numberOfAssets] %d",[group numberOfAssets]);

            };

            assetGroups = [[NSMutableArray alloc] init];

            [library enumerateGroupsWithTypes:ALAssetsGroupAll
                                   usingBlock:assetGroupEnumerator
                                 failureBlock:^(NSError *error) {NSLog(@"A problem occurred");}];
        }

Please help.

2

There are 2 answers

2
CouchDeveloper On

It should be quite obvious that you can't open and store all photos as fullscreen images in an array since this will cause memory pressure and finally a memory failure, which leads to a crash.

Additionally, the statement

[picsTbl reloadData];

might be problematic since it is not clear on which execution context it is executed since it is a completion handler of a system method. Here, if picsTbl is a UITableView is must be the main thread. You should make sure it actually is the case.

You need a different approach for your problem. Specifically, since you are potentially working with large data (given a restricted device) you must ensure you only process one image and only keep one image in memory at a time.

You can get some ideas how to sequentially invoke asynchronous methods - that is, effectively serializing asynchronous methods, here:

Force async tasks to run in sequence

ios programming: Using threads to add multiple images to library

0
Jayaprada On
  • Crash is happening due to excess memory from UIImage
  • We have use @autorelasePool.
  • If you are saving the imgaes into an array then resize it before saving.
  • For Non-ARC

      block = ^(ALAsset *myasset)
    {
      NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    
      // rest of block here
    
      [pool release];     }
    
  • For ARC

    block = ^(ALAsset *myasset)
{
@autoreleasepool{
  // rest of block here

}
}
  • Below is the sample Code

    {

        if(result != nil) 
            if([[result valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypePhoto]) {
                [assetURLDictionaries addObject:[result valueForProperty:ALAssetPropertyURLs]];
    
                NSURL *url= (NSURL*) [[result defaultRepresentation]url];
    
                [library assetForURL:url
                         resultBlock:^(ALAsset *asset) {
                                 @autoreleasepool {
    
                                     UIImage *imageToSave = [UIImage imageWithCGImage:[[asset defaultRepresentation] fullScreenImage]];
                                     CGSize sizeToSave = CGSizeMake(30,30);
                                     UIGraphicsBeginImageContextWithOptions(sizeToSave, NO, 0.f);
                                     [imageToSave drawInRect:CGRectMake(0.f, 0.f, sizeToSave.width, sizeToSave.height)];
                                     UIImage *finalImageToSave = UIGraphicsGetImageFromCurrentImageContext();
                                     UIGraphicsEndImageContext();
                                     NSLog(@"mutableArray.count:%d",mutableArray.count);
                                     if (finalImageToSave!=nil) {
                                         [mutableArray addObject:finalImageToSave];
    
                                     }
                                     if ([mutableArray count]==89)//count
                                     {
                                         [imageArray addObjectsFromArray:mutableArray];
                                         [self allPhotosCollected:imageArray];
                                     }
                                 }
                         }
                        failureBlock:^(NSError *error){
                            [[[UIAlertView alloc]initWithTitle:@"" message:@"operation was not successfull!" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]show];
                            NSLog(@"operation was not successfull!");
                        } ];
            }
        }else{
    
            //handle UI
        }