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:
But the NSData
is nil
as below:
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?
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. :)