Search code examples
iosobjective-cuiimagensdataphotokit

Cannot convert UIImage to NSData when fetched with PhotoKit


My scenario is that I select one of the photos fetched from system album with PhotoKit and presented in my UICollectionView and pass the selected photo (UIImage) to my next UIView and send it to remote server in form of NSData. But when I put breakpoint before sending to track the NSData I found that the UIImage had data with allocated memory while NSData did not.

Here is the code to fetch the UIImage (Please notice that I didn't specify any PHImageRequestOptions object):

NSMutableArray *images = @[].mutableCopy;
PHImageManager *manager = [PHImageManager defaultManager];
PHAsset *asset = _photoPickerCollectionView.pickedAsset;
CGSize targetSize = CGSizeMake(asset.pixelWidth*0.5, asset.pixelHeight*0.5);
[manager requestImageForAsset:asset targetSize:targetSize contentMode:PHImageContentModeAspectFill options:nil resultHandler:^(UIImage *result, NSDictionary *info) {
    _nextView.pickedOne = result;
}];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];

I convert the UIImage to NSData like this:

UIImage *image = _pickedOne;
NSData *imgData = UIImageJPEGRepresentation(image, imageQuality);

When I tracked the variables, the UIImage contains data as below:

enter image description here

But the NSData is nil as below:

enter image description here

And what was ODD is that if I specified an PHImageRequestOptions object for the PHImageManager to request images, the NSData wouldn't be nil. I'm not sure what was changed with or without the PHImageRequestOptions and why it would make such difference.

UPDATE: What I found is that if you specify PHImageRequestOptions to nil then the default options will force it to fetch photos asynchronously which, in my opinion, can be unstable for NSData, so when I specify options.synchronous = YES; it would work.

But in this case, would it cause any retain cycle or some PhotoKit objects won't get released?


Solution

  • The method by default is asynchronous. You need to set options to explicitly make the image fetching synchronous. My strong suggestion for such kind of conversion is to use this API:

    - (PHImageRequestID)requestImageDataForAsset:(PHAsset *)asset options:(nullable PHImageRequestOptions *)options resultHandler:(void(^)(NSData *__nullable imageData, NSString *__nullable dataUTI, UIImageOrientation orientation, NSDictionary *__nullable info))resultHandler;
    

    This returns you the data directly but you will have to make this synchronous as well. This WON'T cause any retain cycles for any objects. Hope this helps. :)