iOS 开发之照片框架详解--PhotoKit(转载)

一、概况


PhotoKit 基本构成的介绍:

  • PHAsset:代表照片库中的一个资源,跟 ALAsset 类似, 通过 PHAsset 可以获取和保存资源
  • PHFetchOptions:获取资源的参数,可以nil,及使用系统默认值
  • PHAssetCollection:PHCollection 的子类,表示一个相册或者一个时刻,后者是一个只能相册(系统提供的特定的一系列相册,例如:最近删除,视频列表, 收藏等等)
  • PHFetchResult:表示一系列的资源的结果集合,也可以是相册的集合,从PHCollection 的类方法中获得
  • PHImageManager:用于处理资源的加载,加载图片的过程带有缓存处理,可以通过传入一个 PHImageRequestOptions:如上面所说,控制加载图片时的一系列参数

这里还有一个额外的概念PHCollectionList,表示一组PHCollection,它本身也是一个PHCollection,因此 PHCollection 作为一个集合,可以包含其他集合,这使得 PhotoKit 的组成比 ALAssetLibrary 要复杂一些。另外与 ALAssetLibrary 相似,一个 PHAsset 可以同时属于多个不同的 PHAssetCollection,最常见的例子就是刚刚拍摄的照片,至少同时属于“最近添加”、“相机胶卷”已经“照片-精选”这三个 PHAssetCollection。

二、PhotoKit 的机制


1、获取资源
在 ALAssetLibrary 中获取数据,无论是相册,还是资源,本质上都是使用枚举的方式,遍历照片库取得相应的数据,并且数据是从 ALAssetLibrary(照片库)- ALAssetGroup(相册)- ALAsset(资源)这一路径逐层获取,这样好处很明显,就是非常符合实际应用中资源的显示路径:照片库 - 相册 - 图片或视频,但由于枚举的方式获取资源,效率低而且不灵活。

而在 PhotoKit 中,则是采用“获取”的方式拉取资源,这些获取的手段,都是一系列形如 class func fetchXXX(,Options:PHFetchOptions)-> PHFetchResult 的类方法,具体使用那个类方法,则会根据获取的是相册、时刻还是资源,这类方法中的 option 充当了过滤器的作用,可以过来相册的类型,日期,名称等,从而获取对于的资源而不需要枚举。例如在前文中累加个的几个小例子:

// 列出所有相册智能相册
PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
// 列出所有用户创建的相册
PHFetchResult *topLevelUserCollections = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil];
// 获取所有资源的集合,并按照资源的创建时间排序
PHFetchOptions *options = [[PHFetchOptions alloc] init];
options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
PHFetchResult *assetsFetchResults = [PHASSet fetchAssetsWithOptions:options];

如前面提到过的那样,从PHAssetCollection 中获取到的可以使相册也可以是资源,但无论是哪种内容,都统一使用PHFetchResult 对象封装起来,因此虽然PHAssetCollection 获取到的结果可能是多样的,但通过PHFetchResult 就可以使用统一的方法去处理这些内容(即遍历 PHFetchResult)。例如扩展上面的例子:

// 列出所有相册智能相册
PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
for (NSInteger i = 0; i < fetchResult.count; i++) {
    PHCollection *collection = fetchResult[i];
    if (collection isKindOfClass:[PHAssetCollection class]]) {
        PHAssetCollection *assetCollection =   (PHAssetCollection *)collection;
        PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:assetCollection options:fetchOptions];
    } else {
        NSAssert(NO, @"Fetch collection not PHCollection:%@", collection);
    }
}
// 获取所有资源的集合,并按资源的创建时间排序
PHFetchOptions *options = [[PHFetchOptions alloc] init];
options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
PHFetchResult *assetsFetchResults = [PHAsset fetchAssetsWithOptions:options];
// 这时 assetsFetchResults 中包含的,应该就是各个资源(PHAsset)
for (NSInteger i = 0; i < fetchResult.count; i++) {
    // 获取一个资源(PHAsset)
    PHAsset *asset = fetchResult[i];
}

2.获取图像的方式与坑点

经过了上面的步骤,已经可以了解到如何在 PhotoKit 中获取到代表资源的 PHAsset 了,但与 ALAssetLibrary 中从 ALAsset 中直接获取图像的方式不同,PhotoKit 无法直接从 PHAsset 的实例中获取图像,而是引入了一个管理器?PHImageManager 获取图像。PHImageManager 是通过请求的方式拉取图像,并可以控制请求得到的图像的尺寸、剪裁方式、质量,缓存以及请求本身的管理(发出请求、取消请求)等。而请求图像的方法是 ?PHImageManager 的一个实例方法:

- (PHImageRequestID)requestImageForAsset:(PHAsset *)asset targetSize(CGSize)targetSize contentMode(PHImageContentMode)contentMode options:(nullable PHImageRequestOptions *)options resultHandler:(void (^)(UIImage *__nullable result, NSDictionary *__nullable info))resultHandler;

这个方法中的参数坑点不少,下面逐个参数列举一下其作用及坑点:

  • asset, 图像对应的 PHAsset。
  • targetSize,需要获取的图像的尺寸,如果输入的尺寸大于资源原图的尺寸,则只会返回原图。需要注意在 PHImageManager 中,所有的尺寸都是用 Pixel 作为单位,因此这里想要获得正确大小的图像,需要把输入的尺寸转化为 Pixel。如果返回原图尺寸,可以传入 PhotoKit 中预先定义好的常量PHImageManagerMaximumSize,表示返回可选范围内的最大尺寸,即原图尺寸。
  • contentMode,图像的剪裁方式,与?UIView 的 contentMode 参数相似,控制照片应该以按比例缩放还是按比例填充的方式放到最终展示的容器内。注意如果 targetSize 传入 PHImageManagerMaximumSize,则 contentMode 无论传入什么值都会被视为?PHImageContentModeDefault。
  • options,一个?PHImageRequestOptions 的实例,可以控制的内容相当丰富,包括图像的质量、版本,也会有参数控制图像的剪裁,下面再展开说明。
  • resultHandler,请求结束后被调用的 block,返回一个包含资源对于图像的 UIImage 和包含图像信息的一个 NSDictionary, 在整个请求的周期中,这个block 可能会多次调用,关于这点连同 options 参数在下面展开说明。

你可能感兴趣的:(iOS 开发之照片框架详解--PhotoKit(转载))