PHImageManager
2015-12-22 20:32
609 查看
现在的app中,对照片和视频的操作非常频繁,如:各类软件个人图像的选取,社交软件照片及视频的分享,评论上图等。。。IOS8中更新的PHImageManager对于想要操控手机图片或视频的程序猿们无疑是最好的选择。
获取手机照片并回显
大家都应该用过手机QQ,当我们要用QQ发送图片给小伙伴时,点击发送图片icon,QQ会非常贴心的将最近几张照片给我们呈现出来,供我们选择。用PHImageManager能很快的实现这样一个功能。在此做个简单的类似的实现:
在项目build phase中添加Libraries Photos.framework 并在vc中引入头文件
获取访问照片权限
构建这样一个场景:在当前viewcontroller中点击button 然后全屏显示最新拍摄的照片或者截屏图片。UI代码如下:
在Extension中定义全局变量
然后再.m中加入
实现showImage方法 显示图片,隐藏Button
有两个方法看着比较陌生
第一个:
该方法用作遍历资源库 返回特定类型的资源,mediaType可选四个值,对应关系分别为:PHAssetMediaTypeUnknown–所有 PHAssetMediaTypeImage–图片 PHAssetMediaTypeVideo–视频 PHAssetMediaTypeAudio–音频。
PHFetchResult对应一组资源,PHAsset对应单个资源。
options是搜索条件 如:搜索自己喜爱的照片 并且按照时间上升顺序排列:
第二个:
该方法用作获取特定的PHAsset所对应的图片,返回值为PHImageRequestID类型(实际上是32位int类型)的ID,可以用作取消加载还未加载完成的该请求。- (void)cancelImageRequest:(PHImageRequestID)requestID;
targetSize是你所需要返回的image尺寸,PHImageManagerMaximumSize为原图片尺寸
contentMode是如果原image尺寸与targetSize不相等,用哪种填充的mode,有两个可选值:PHImageContentModeAspectFill–缩放长宽完全填充 PHImageContentModeAspectFit–只缩放长宽中比较大的那个,来等于targetSize。
options:定义请求方式,可为nil,下文会详细介绍,
resultHandler:block 当image完全请求过来后调用。
现在 运行程序就能看到效果啦。
获取图片并缓存
如果需求为要在一个页面,同时显示大量图片,for循环调用上诉方法肯定是不行的,requestImageForAsset会有延时,而达到这一效果,我们可以先缓存下来所有的图片,然后用requestImageForAsset,根据PHImageManage的加载机制,能做到同时显示。
缓存图片方法代码如下:
经过此缓存后,再用RequestImageForAsset:targetSize:contentMode:options:resultHandler:方法时便能直接从缓存中加载image,从而直接执行resultHandler内的block,特别注意,无延时加载的前提条件是,此时的targetSize 与 缓存时的targetSize必须一样,不然此方法会去图片库重新请求资源加载成image而不会走缓存。
图片请求回显方式详解 PHImageRequestOptions
之前的RequestImageForAsset 和 startCachingImagesForAssets两个方法中 option都设置的是nil。PHImageRequestOptions是用来控制加载什么一级用什么样的方式。下面介绍其主要属性:
* networkAccessAllowed Bool 如果需要,是否允许从iCloud下载图片。
* normalizedCropRect CGRect 指定一个rect来截取原图片,rect以原图片为坐标系。
* synchronous Bool 同步加载。默认是NO。(只有当resultHandler block执行完后 该方法才执行完毕)。
* deliveryMode PHImageRequestOptionsDeliveryMode
* PHImageRequestOptionsDeliveryMode是一个enum类型的,它囊括了非常复杂的操作,有三个值分别对应:
PHImageRequestOptionsDeliveryModeOpportunistic 当选用此项时,Photos会在你请求时给你提供一个或者多个结果,这就意味着resultHandler block可能会执行一次或多次,例如
Photos会先给你一个低分辨率的图片让你暂时显示,然后加载出高质量的图片后再次给你。如果PHImageManager已经pre-cache了图片,那result handler便只会执行一次。另外,如果synchronous属性为NO,此选项是不起作用的。
PHImageRequestOptionsDeliveryModeHighQualityFormat 当请求image时 不管请求需要多长时间完成,Photos只会提供高质量的image。另外,当synhronous属性为YES 或者使用requestImageDataForAsset:options:resultHandler: 方法时,这个选项是默认且唯一的。
PHImageRequestOptionsDeliveryModeFastFormat 当请求image时,高质量的图片或低质量的图片,谁加载的快 便显示谁。另外Photos也能通过检查info字典(resultHandler中的参数)里的PHImageResultIsDegradedKey值来判定传高质量或者低质量的图片。
之前运行时,应该能发现 在图片出现前会有短暂的图片背景色显示。现在我们加上option后再请求图片:
此时便不会有那个问题了。
ps:关于PHImageRequestOptionsDeliveryMode enum中值的意思我是翻译的apple官方文档,其中有一个逻辑错误就是,按照官方文档逻辑来看,在任何情况下PHImageRequestOptionsDeliveryModeOpportunistic属性都不会起作用。对此问题我也google过,然后发现mattt大大的文章中也是直接搬过来的,在Twitter上问了他,问题确实存在,以下是我与他的私信过程:
获取手机照片并回显
大家都应该用过手机QQ,当我们要用QQ发送图片给小伙伴时,点击发送图片icon,QQ会非常贴心的将最近几张照片给我们呈现出来,供我们选择。用PHImageManager能很快的实现这样一个功能。在此做个简单的类似的实现:
在项目build phase中添加Libraries Photos.framework 并在vc中引入头文件
#import <Photos/Photos.h>
获取访问照片权限
- (void)requestPermissons { //获取当前状态:PHAuthorizationStatusNotDetermined--未知 // PHAuthorizationStatusRestricted--受限制的(用户不能更改某个app的此状态,或许某些活动限制设置能改变如:家长模式) // PHAuthorizationStatusDenied--拒绝访问 // PHAuthorizationStatusAuthorized--可以访问 PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; __weak RCCachingLocalImage *weakSelf = self; if (status == PHAuthorizationStatusNotDetermined) { [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { if (status == PHAuthorizationStatusAuthorized) { //获取手机照片库 //[weakSelf loadImages]; }else{ //弹出提示信息 [weakSelf alertMsg]; } }]; }else if(status == PHAuthorizationStatusAuthorized){ //获取手机照片库 //[self loadImages]; }else{ //弹出提示信息 [self alertMsg]; } }
构建这样一个场景:在当前viewcontroller中点击button 然后全屏显示最新拍摄的照片或者截屏图片。UI代码如下:
在Extension中定义全局变量
@interface RCCachingLocalImage() @property (nonatomic, strong) NSMutableArray *assets;//用于存储所有的照片。 @property (nonatomic, strong) UIButton *showImgBnt; @property (nonatomic, strong) UIImageView *imgView; @end
然后再.m中加入
- (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; [self requestPermissons]; UIButton *navButton = [UIButton new]; navButton.frame = CGRectMake(130, CGRectGetHeight(self.view.frame) - 200, CGRectGetWidth(self.view.frame)-2*130, 40); navButton.backgroundColor = [UIColor blueColor]; [navButton setTitle:@"Show Image" forState:UIControlStateNormal]; [navButton addTarget:self action:@selector(showImage) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:navButton]; self.showImgBtn = navButton; UIImageView *imageView = [UIImageView new]; imageView.backgroundColor = [UIColor greenColor]; imageView.frame = self.view.frame; [self.view addSubview:imageView]; self.imgView = imageView; self.imgView.hidden = YES; }
实现showImage方法 显示图片,隐藏Button
- (void)showImage { self.showImgBnt.hidden = YES; self.imgView.hidden = NO; //获取相册里所有的照片 PHFetchResult *result = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil]; self.assets = [[NSMutableArray alloc] init]; [result enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { if ([obj isKindOfClass:[PHAsset class]]) { [self.assets addObject:obj]; } }]; //最后一张图为最新 PHAsset *asset = [self.assets lastObject]; PHImageManager *manager = [PHImageManager defaultManager]; [manager requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFill options:nil resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { [< 4000 span class="hljs-keyword">self.imgView setImage:result]; }]; }
有两个方法看着比较陌生
第一个:
+ (PHFetchResult<PHAsset *> *)fetchAssetsWithMediaType:(PHAssetMediaType)mediaType options:(nullable PHFetchOptions *)options;
该方法用作遍历资源库 返回特定类型的资源,mediaType可选四个值,对应关系分别为:PHAssetMediaTypeUnknown–所有 PHAssetMediaTypeImage–图片 PHAssetMediaTypeVideo–视频 PHAssetMediaTypeAudio–音频。
PHFetchResult对应一组资源,PHAsset对应单个资源。
options是搜索条件 如:搜索自己喜爱的照片 并且按照时间上升顺序排列:
PHFetchOptions *option = [[PHFetchOptions alloc] init]; option.predicate = [NSPredicate predicateWithFormat:@"favorite == YES"]; option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]]; PHFetchResult *result = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:option];
第二个:
- (PHImageRequestID)requestImageForAsset:(PHAsset *)asset targetSize:(CGSize)targetSize contentMode:(PHImageContentMode)contentMode options:(nullable PHImageRequestOptions *)options resultHandler:(void (^)(UIImage *__nullable result, NSDictionary *__nullable info))resultHandler;
该方法用作获取特定的PHAsset所对应的图片,返回值为PHImageRequestID类型(实际上是32位int类型)的ID,可以用作取消加载还未加载完成的该请求。- (void)cancelImageRequest:(PHImageRequestID)requestID;
targetSize是你所需要返回的image尺寸,PHImageManagerMaximumSize为原图片尺寸
contentMode是如果原image尺寸与targetSize不相等,用哪种填充的mode,有两个可选值:PHImageContentModeAspectFill–缩放长宽完全填充 PHImageContentModeAspectFit–只缩放长宽中比较大的那个,来等于targetSize。
options:定义请求方式,可为nil,下文会详细介绍,
resultHandler:block 当image完全请求过来后调用。
现在 运行程序就能看到效果啦。
获取图片并缓存
如果需求为要在一个页面,同时显示大量图片,for循环调用上诉方法肯定是不行的,requestImageForAsset会有延时,而达到这一效果,我们可以先缓存下来所有的图片,然后用requestImageForAsset,根据PHImageManage的加载机制,能做到同时显示。
缓存图片方法代码如下:
- (void)loadImages { NSLog(@"loadImages"); PHFetchResult *result = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil]; NSLog(@"%lu",[result count]); self.assets = [[NSMutableArray alloc] init]; [result enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { if ([obj isKindOfClass:[PHAsset class]]) { [self.assets addObject:obj]; } }]; PHCachingImageManager *cachingImage = [[PHCachingImageManager alloc] init]; [cachingImage startCachingImagesForAssets:self.assets targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFit options:nil]; }
经过此缓存后,再用RequestImageForAsset:targetSize:contentMode:options:resultHandler:方法时便能直接从缓存中加载image,从而直接执行resultHandler内的block,特别注意,无延时加载的前提条件是,此时的targetSize 与 缓存时的targetSize必须一样,不然此方法会去图片库重新请求资源加载成image而不会走缓存。
图片请求回显方式详解 PHImageRequestOptions
之前的RequestImageForAsset 和 startCachingImagesForAssets两个方法中 option都设置的是nil。PHImageRequestOptions是用来控制加载什么一级用什么样的方式。下面介绍其主要属性:
* networkAccessAllowed Bool 如果需要,是否允许从iCloud下载图片。
* normalizedCropRect CGRect 指定一个rect来截取原图片,rect以原图片为坐标系。
* synchronous Bool 同步加载。默认是NO。(只有当resultHandler block执行完后 该方法才执行完毕)。
* deliveryMode PHImageRequestOptionsDeliveryMode
* PHImageRequestOptionsDeliveryMode是一个enum类型的,它囊括了非常复杂的操作,有三个值分别对应:
PHImageRequestOptionsDeliveryModeOpportunistic 当选用此项时,Photos会在你请求时给你提供一个或者多个结果,这就意味着resultHandler block可能会执行一次或多次,例如
Photos会先给你一个低分辨率的图片让你暂时显示,然后加载出高质量的图片后再次给你。如果PHImageManager已经pre-cache了图片,那result handler便只会执行一次。另外,如果synchronous属性为NO,此选项是不起作用的。
PHImageRequestOptionsDeliveryModeHighQualityFormat 当请求image时 不管请求需要多长时间完成,Photos只会提供高质量的image。另外,当synhronous属性为YES 或者使用requestImageDataForAsset:options:resultHandler: 方法时,这个选项是默认且唯一的。
PHImageRequestOptionsDeliveryModeFastFormat 当请求image时,高质量的图片或低质量的图片,谁加载的快 便显示谁。另外Photos也能通过检查info字典(resultHandler中的参数)里的PHImageResultIsDegradedKey值来判定传高质量或者低质量的图片。
之前运行时,应该能发现 在图片出现前会有短暂的图片背景色显示。现在我们加上option后再请求图片:
- (void)showImage { self.showImgBnt.hidden = YES; self.imgView.hidden = NO; PHAsset *asset = [self.assets firstObject]; PHImageManager *manager = [PHImageManager defaultManager]; PHImageRequestOptions *option = [[PHImageRequestOptions alloc] init]; option.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat; option.synchronous = YES; [manager requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFill options:option resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { [self.imgView setImage:result]; }]; }
此时便不会有那个问题了。
ps:关于PHImageRequestOptionsDeliveryMode enum中值的意思我是翻译的apple官方文档,其中有一个逻辑错误就是,按照官方文档逻辑来看,在任何情况下PHImageRequestOptionsDeliveryModeOpportunistic属性都不会起作用。对此问题我也google过,然后发现mattt大大的文章中也是直接搬过来的,在Twitter上问了他,问题确实存在,以下是我与他的私信过程:
相关文章推荐
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 不可修补的 iOS 漏洞可能导致 iPhone 4s 到 iPhone X 永久越狱
- iOS 12.4 系统遭黑客破解,漏洞危及数百万用户
- 每日安全资讯:NSO,一家专业入侵 iPhone 的神秘公司
- [转][源代码]Comex公布JailbreakMe 3.0源代码
- 按右键另存图片只能存BMP
- photoshop去除图片上的水印
- upload上传单张图片
- 图片引发的溢出危机(图)
- C#实现把彩色图片灰度化代码分享
- C#将图片和字节流互相转换并显示到页面上
- C#监控文件夹并自动给图片文件打水印的方法
- 纯CSS实现的当鼠标移上图片添加阴影效果代码
- C#实现打开画图的同时载入图片、最大化显示画图窗体的方法
- 随鼠标移动的图片或文字特效代码
- CSS 图片横向排列实现代码
- C#实现将Email地址转成图片显示的方法
- 超级经典一套鼠标控制左右滚动图片带自动翻滚