PHImageManager crashing after many image requests

2.6k views Asked by At

I'm trying to grab all of the users PHAsset with PHAssetMediaTypeImage and then iterate through them, getting the corresponding UIImages one at a time. I have about 2k photos on my iPhone 5 and this code crashes after iterating through 587 of them.

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

PHImageManager *manager = [PHImageManager defaultManager];
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.synchronous = YES;
__block int i = 0;
for (PHAsset *result in fr)
{

    [manager requestImageForAsset:result targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFill options:options resultHandler:^(UIImage *image, NSDictionary *info) {
        NSLog(@"%d", i);
        i++;
    }];
}

The exception reads EXC_BAD_ACCESS (code=1, address=0x0). Any help pointing me in the right direction on this will be enormously appreciated.

2

There are 2 answers

0
CGR On

The problem for me was found in the this line of code

   PHImageManager.defaultManager().requestImageForAsset(asset, targetSize: PHImageManagerMaximumSize, contentMode: .AspectFill, options: nil, resultHandler: {(result, info) in cell.setThumbnailImage(result)
    })

The parameter, targetSize was passed the value of PHImageManagerMaximumSize which was the culprit. I changed it to lCgSize, lCgSize = CGSizeMake(105, 105); resolved the issue.

According to the documentation PHImageManagerMaximumSize

When you use the PHImageManagerMaximumSize option, Photos provides the largest image available for the asset without scaling or cropping. (That is, it ignores the resizeMode option.)

So, this explains the problem. I believe if it was a single image, it should not be a problem but if it was many images, the device would run out of memory.

0
Stephen Mueller On

Closing the loop on this one. The images don't get released until the for loop completes so you need to put an @autoreleasepool to drain the pool after each iteration of the loop, like so

PHFetchResult *fr = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil];
PHImageManager *manager = [PHImageManager defaultManager];
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.synchronous = YES;
__block int i = 0;
for (PHAsset *result in fr)
{
    @autoreleasepool {
    [manager requestImageForAsset:result targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFill options:options resultHandler:^(UIImage *image, NSDictionary *info) {
            NSLog(@"%d", i);
            i++;
        }];
    }
}