您的位置:首页 > 移动开发 > IOS开发

PHImageManager

2015-12-22 20:32 609 查看
现在的app中,对照片和视频的操作非常频繁,如:各类软件个人图像的选取,社交软件照片及视频的分享,评论上图等。。。IOS8中更新的PHImageManager对于想要操控手机图片或视频的程序猿们无疑是最好的选择。

获取手机照片并回显

大家都应该用过手机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上问了他,问题确实存在,以下是我与他的私信过程:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ios 图片