工做缘由,须要处理接入一个视频模块,在视频选择的时候遇到了一个不太容易发现的bug,产生的缘由是因为手机内存小,而用户又打开了相册同步iCloud,git
加载中的图片github
在这时,若是本地可用内存太小,会致使
将本地相册中的图片或视频删除只留缩略图,若是App调用的时候想要选取这种图片就须要从iCloud云中进行下载,
才能获取原图或原视频。ide
下面po下解决方案:fetch
若是你以前处理过相册问题,那么对以下的代码确定不陌生,就是很普通的两个系统级别的请求回调,获取对应的图片,视频。atom
// get Image [[PHImageManager defaultManager] requestImageDataForAsset:asset options:nil resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { }]; // get Video [[PHImageManager defaultManager] requestPlayerItemForVideo:asset options:nil resultHandler:^(AVPlayerItem * _Nullable playerItem, NSDictionary * _Nullable info) { if (completion) completion(playerItem,info); }];
可是每每以前没有注意到第二个输入 options
是用来干吗的,
其实解决方案就来自于这个 PHImageRequestOptions
,PHVideoRequestOptions
。spa
这这两个 options
都有一个共同的参数就是.net
@property (nonatomic, assign, getter=isNetworkAccessAllowed) BOOL networkAccessAllowed; // if necessary will download the image from iCloud (client can monitor or cancel using progressHandler). Defaults to NO (see start/stopCachingImagesForAssets)
系统的解释也很详细,若是赋值 YES
,那么容许从 iCloud
中获取图片和视频,默认是 NO
。线程
虽然这个问题解决不是很难,可是每每容易被忽略,因此记录一下。code
这里很是感谢@半迟尘大大的TZImagePickerController的源码,这个是一个很是靠谱的相册选择图片视频的库,而且处于仍在维护中。感兴趣的能够连接过去看一看源码,写的很好。orm
博主博客@HarwordLiu
下面po一下完整的这个问题的解决代码:
/// Get Video - (void)getVideoOutputPathWithAsset:(PHAsset *)asset completion:(void (^)(NSString *outputPath))completion { PHVideoRequestOptions* options = [[PHVideoRequestOptions alloc] init]; options.version = PHVideoRequestOptionsVersionOriginal; options.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic; options.networkAccessAllowed = YES; [[PHImageManager defaultManager] requestAVAssetForVideo:asset options:options resultHandler:^(AVAsset* avasset, AVAudioMix* audioMix, NSDictionary* info){ // NSLog(@"Info:\n%@",info); AVURLAsset *videoAsset = (AVURLAsset*)avasset; // NSLog(@"AVAsset URL: %@",myAsset.URL); [self startExportVideoWithVideoAsset:videoAsset completion:completion]; }]; } /// Get Image - (PHImageRequestID)getPhotoWithAsset:(PHAsset *)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *, NSDictionary *, BOOL isDegraded))completion { PHAsset *phAsset = (PHAsset *)asset; CGFloat aspectRatio = phAsset.pixelWidth / (CGFloat)phAsset.pixelHeight; CGFloat pixelWidth = photoWidth * 2.0; CGFloat pixelHeight = pixelWidth / aspectRatio; CGSize imageSize = CGSizeMake(pixelWidth, pixelHeight); // 修复获取图片时出现的瞬间内存太高问题 PHImageRequestOptions *option = [[PHImageRequestOptions alloc] init]; option.resizeMode = PHImageRequestOptionsResizeModeFast; PHImageRequestID imageRequestID = [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:imageSize contentMode:PHImageContentModeAspectFill options:option resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]); if (downloadFinined && result) { if (completion) completion(result,info,[[info objectForKey:PHImageResultIsDegradedKey] boolValue]); } // Download image from iCloud / 从iCloud下载图片 if ([info objectForKey:PHImageResultIsInCloudKey] && !result) { PHImageRequestOptions *option = [[PHImageRequestOptions alloc]init]; option.networkAccessAllowed = YES; option.resizeMode = PHImageRequestOptionsResizeModeFast; [[PHImageManager defaultManager] requestImageDataForAsset:asset options:option resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { UIImage *resultImage = [UIImage imageWithData:imageData scale:0.1]; if (completion) completion(resultImage,info,[[info objectForKey:PHImageResultIsDegradedKey] boolValue]); }]; } }]; return imageRequestID; }
https://stackoverflow.com/questions/31966571/check-given-phasset-is-icloud-asset
第一种方法
[cloudAlbums enumerateObjectsUsingBlock:^(PHAssetCollection *collection, NSUInteger idx, BOOL *stop) { PHFetchResult *result = [PHAsset fetchAssetsInAssetCollection:collection options:fetchOptions]; [result enumerateObjectsUsingBlock:^(PHAsset *asset, NSUInteger idx, BOOL *stop) { PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init]; options.resizeMode = PHImageRequestOptionsResizeModeFast; options.synchronous = YES;
__block BOOL isICloudAsset = NO; [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:imageSize contentMode:PHImageContentModeAspectFit options:options resultHandler:^(UIImage *result, NSDictionary *info) { //根据请求会调中的参数重 NSDictionary *info 是否有cloudKey 来判断是不是 iCloud if ([info objectForKey: PHImageResultIsInCloudKey].boolValue) { isICloudAsset = YES; } }]; }]; }];
第二种方法(实际上是同一种)
__block BOOL isPhotoInICloud = NO; PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init]; options.networkAccessAllowed = YES; options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat; // 下载iCloud 图片的进度回调 只要图片是在icloud中 而后去请求图片就会走这个回调 若是图片没有在iCloud中不回走这个回调 //里面的会调中的参数重 NSDictionary *info 是否有cloudKey 来判断是不是 iCloud 处理UI放到主线程 options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info){ isPhotoInICloud = YES;
}); //上面的进度下载完了以后才会掉用resultHandler 回调 [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFit options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { if (isPhotoInICloud) { // Photo is in iCloud. } });