demo下载地址在最下方
一、AssetsLibrary
iOS提供的AssetsLibrary是用来读取和操作本地相册的,相当于app与系统相册之间的桥梁,该框架提供了以下的几个类:ALAssetsLibrary,ALAssetsGroup,ALAsset,ALAssetsFilter,ALAssetRepresentation
ALAssetsLibrary:本地资源库对象
ALAssetsGroup:本地相册分组对象,本地有多少个相薄就会有几个ALAssetsGroup类型的对象。
ALAsset:从本地相册获取的图片或者视频的对象都是ALAsset类型的对象。
ALAssetsFilter:对本地所有资源的过滤筛选,可以选择只获取照片,只获取视频,或者获取所有的资源。
ALAssetRepresentation:获取视频或者图片的url,文件名,二进制数据,封面缩略图等。
在这里先介绍一些比较常用的方法:
ALAssetsLibrary
1、获得相册的组别
- (void)enumerateGroupsWithTypes:(ALAssetsGroupType)types usingBlock:(ALAssetsLibraryGroupsEnumerationResultsBlock)enumerationBlock failureBlock:(ALAssetsLibraryAccessFailureBlock)failureBlock
在这个方法可以获取分组的列表,包括名称、封面图片等,其中有以下几个type:ALAssetsGroupLibrary,ALAssetsGroupAlbum,ALAssetsGroupEvent,ALAssetsGroupFaces,ALAssetsGroupSavedPhotos,ALAssetsGroupPhotoStream,ALAssetsGroupAll。
2、返回一个ALAsset对象
- (void)assetForURL:(NSURL *)assetURL resultBlock:(ALAssetsLibraryAssetForURLResultBlock)resultBlock failureBlock:(ALAssetsLibraryAccessFailureBlock)failureBlock
3、返回一个ALAssetsGroup对象
- (void)groupForURL:(NSURL *)groupURL resultBlock:(ALAssetsLibraryGroupResultBlock)resultBlock failureBlock:(ALAssetsLibraryAccessFailureBlock)failureBlock
ALAssetsGroup
ALAssetsGroup是获取相册组的类,可以通过这个类提供的方法来获取相册组的信息
1、获得名称、类型、ID、NSURL
- (id)valueForProperty:(NSString *)property;
property可以是:
ALAssetsGroupPropertyName:名称
ALAssetsGroupPropertyType:类型
ALAssetsGroupPropertyPersistentID:ID
ALAssetsGroupPropertyURL :NSURL
2、获得相册分组的封面图片
- (CGImageRef)posterImage;
3、过滤器
- (void)setAssetsFilter:(ALAssetsFilter *)filter
ALAssetsFilter一下这些方法是过滤类型:
+ (ALAssetsFilter *)allPhotos;
+ (ALAssetsFilter *)allVideos;
+ (ALAssetsFilter *)allAssets;
4、获得相册的组的数量
- (NSInteger)numberOfAssets;
5. 通过相册组获取里面的图片
- (void)enumerateAssetsUsingBlock:(ALAssetsGroupEnumerationResultsBlock)enumerationBlock
- (void)enumerateAssetsWithOptions:(NSEnumerationOptions)options usingBlock:(ALAssetsGroupEnumerationResultsBlock)enumerationBlock
- (void)enumerateAssetsAtIndexes:(NSIndexSet *)indexSet options:(NSEnumerationOptions)options usingBlock:(ALAssetsGroupEnumerationResultsBlock)enumerationBlock
ALAssetRepresentation
ALAssetRepresentation对象封装了一个给定对象ALAsset对象的描述
具体参考:
blog.csdn.net/meegomeego/article/details/21165145
ALAsset
- (id)valueForProperty:(NSString *)property;
有以下几个类型:
ALAssetPropertyType 资源的类型(照片,视频)
ALAssetPropertyLocation 资源地理位置(无位置信息返回null)
ALAssetPropertyDuation 播放时长(照片返回ALErorInvalidProperty)
ALAssetPropertyOrientation 方向(共有8个方向,参见:ALAssetOrientation)
ALAssetPropertyDate 拍摄时间(包含了年与日时分秒)
ALAssetPropertyRepresentations 描述(打印看了下,只有带后缀的名称)
ALAssetPropertyURLs(返回一个字典,键值分别是文件名和文件的url)
ALAssetPropertyAssetURL 文件的url
//得到缩略图
- (CGImageRef)thumbnail;
以上是对AssetsLibrary的总结,下面是对photokit框架的总结
二、photokit
photokit是iOS8出的一个新的图片选择框架,用来取代上述AssetsLibrary框架,相比较AssetsLibrary来说photokit更加灵活,而在iOS9中,AssetsLibrary已经被弃用,也不支持livephoto,并且使用AssetsLibrary时,图片的分辨率会变低,接下来就介绍一下photokit。
Photos中有以下几个类:
PHAdjustmentData:当用户编辑资源,照片与修改后的图像或视频数据保存在一个PHAdjustmentData对象中
PHAsset:代表照片库中的一个资源实体,可以理解为一张照片,在打印的时候,可以清楚的看见里面包含了照片的时间、标题等信息
PHAssetChangeRequest:使用PHAssetChangeRequest对象来创建、删除和修改相片库里面的PHAsset对象
PHAssetCollectionChangeRequest:使用PHAssetCollectionChangeRequest对象来创建、删除和修改相片库里面的PHAssetCollection对象
PHAssetCreationRequest:使用PHAssetCreationRequest对象构造一个新的照片或视频,并将其添加到照片库
PHAssetResource:一个PHAssetResource对象表示在照片库中的照片或视频资源(也就是一个PHAsset对象)相关联的基础数据资源之一,使用PHAssetResourceManager类获取它
PHAssetResourceManager:PHAssetResourceManager对象提供了访问与照片资源相关的资源基础数据存储方法
PHChange:PHChange对象来通知的照片库中的资源的一些变法,比如增加和删除
PHCollection:PHAssetCollection对象表示一组照片或视频资源。包括时刻和相册中可见照片应用,以及特殊的集合,如共享照片流。
PHCollectionListChangeRequest:使用PHCollectionListChangeRequest对象在一个照片库中创建、删除或修改PHCollectionList对象。
PHContentEditingInput:PHContentEditingInput对象描述资产用于编辑元数据
PHContentEditingOutput:PHContentEditingOutput对象表示编辑照片资产的照片或视频内容的结果
PHFetchOptions:获取资源时的检索参数,可以传 nil,即使用系统默认值
PHFetchResult:通过PHFetchResult来获取照片实体的有序列表
PHImageManager:PHImageManager对象提供用于加载与PHAsset对象相关联的图像或视频数据的方法。使用这些方法来获取全尺寸照片资产或缩略图,或者检索AV Foundation对象播放,导出和操纵的视频资产。
PHLivePhoto:用来获取LivePhoto实体
PHObject:照片等实体的抽象类
PHPhotoLibrary:PHPhotoLibrary对象表示用户的照片库整套资源和收藏的照片,包括存储在本地设备上在iCloud的照片对象。
PhotosTypes:与Photos框架相关的类型的枚举
使用photokit最直观明了的地方就是一下这个关系:
PHCollectionList,它表示一组 PHCollection,它本身也是一个 PHCollection,因此 PHCollection 作为一个集合,可以包含其他集合,这使得 PhotoKit 的组成比 ALAssetLibrary 要复杂一些。另外与 ALAssetLibrary 相似,一个 PHAsset 可以同时属于多个不同的 PHAssetCollection,最常见的例子就是刚刚拍摄的照片,至少同时属于“最近添加”、“相机胶卷”以及“照片 - 精选”这三个 PHAssetCollection,他们的关系如下图:
photokit的机制:
采用“获取”的方式拉取资源,从 PHAssetCollection 中获取到的可以是相册也可以是资源,但无论是哪种内容,都统一使用 PHFetchResult 对象封装起来,因此虽然 PHAssetCollection 获取到的结果可能是多样的,但通过 PHFetchResult 就可以使用统一的方法去处理这些内容(即遍历 PHFetchResult)
// 列出所有相册智能相册
PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
// 这时 smartAlbums 中保存的应该是各个智能相册对应的 PHAssetCollection
for (NSInteger i = 0; i < fetchResult.count; i++) {
// 获取一个相册(PHAssetCollection)
PHCollection *collection = fetchResult[i];
if ([collection isKindOfClass:[PHAssetCollection class]]) {
PHAssetCollection *assetCollection = (PHAssetCollection *)collection;
// 从一个相册中获取的PHFetchResult中包含的才是PHAsset
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];
}
到了这里已经成功取出了PHAsset,接下来做的操作就是获取图片
可以首先进行一下设置
PHImageRequestOptions *reques = [[PHImageRequestOptions alloc]init];
reques.synchronous = NO;//获取图片方式是否开启异步
reques.resizeMode = PHImageRequestOptionsResizeModeFast;
reques.deliveryMode = PHImageRequestOptionsDeliveryModeFastFormat;
此时可以进行图片获取了:
- (PHImageRequestID)requestImageForAsset:(PHAsset *)asset
targetSize:(CGSize)targetSize
contentMode:(PHImageContentMode)contentMode
options:(nullable PHImageRequestOptions *)options
resultHandler:(void (^)(UIImage *__nullable result, NSDictionary *__nullable info))resultHandler;
resizeMode对应以下三个属性:
1、PHImageRequestOptionsResizeModeNone,
2、PHImageRequestOptionsResizeModeFast, //根据传入的size,迅速加载大小相匹配(略大于或略小于)的图像
3、PHImageRequestOptionsResizeModeExact //精确的加载与传入size相匹配的图像
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值来判定传高质量或者低质量的图片。
targetSize
需要获取的图像的尺寸,如果输入的尺寸大于资源原图的尺寸,只返回原图
contentMode
图像的裁剪方式,与UIView的contentMode参数相似,控制图片是按比例缩放还是按比例填充的方式放在展示的控件中,但如果传入的targetSize是PHImageManagerMaximumSize,contentMode不管传什么值都是PHImageContentModeDefault;
这样整个调取图片的过程就已介绍完毕,最后可以得到一个包含资源对于图像的UIImage和一个包含图像信息的NSDictionary,而在整个过程中,这个block会被多次调用,通俗来说就是在开始的时候给你放一张低质量的图上去,等它拿完之后给你呈现出高清图,具体的效果可以查看微信聊天发图片时大图预览,滑动时会先出现一张模糊的图片,然后马上呈现高清图片。
以上就是我对AssetsLibrary以及photokit的大致总结,这段时间通过在项目中进行实际的使用操作后发现了两者之间的区别:
首先就是二者的机制:
1、在 ALAssetLibrary 中获取数据,无论是相册,还是资源,本质上都是使用枚举的方式,遍历照片库取得相应的数据,并且数据是从 ALAssetLibrary(照片库) - ALAssetGroup(相册)- ALAsset(资源)这一路径逐层获取,即使有直接从 ALAssetLibrary 这一层获取 ALAsset 的接口,本质上也是枚举 ALAssetLibrary 所得,并不是直接获取,这样的好处很明显,就是非常符合实际应用中资源的显示路径:照片库 - 相册 - 图片或视频,但由于采用枚举的方式获取资源,效率低而且不灵活。而在 PhotoKit 中,则是采用“获取”的方式拉取资源,通过上文的机制可以得知。
2、由于二者的机制以及层次关系问题,二者获取到的资源也不一样,所以iOS会在iOS9中开始废弃ALAssetLibrary而采用photokit。ALAssetLibrary中获取所有相册资源使用的ALAssetsGroupAll属性,而到了iOS9之后,对于个人收藏等一张图片可以同时存在于多个相簿的资源来说,就会取不到这些公用相簿,而photokit的PHCollectionList的关系就可以取到这些资源,从而可以方便并且高效的达到我们需要的效果。
3、从获取资源的方式来看,photokit比ALAssetLibrary更加高效并且更加灵活。
以上是我最近实践发现的一些两者的区别。如果还有其他的,希望大家可以在评论区留言给我我会再更新补充。接下来是我最近项目使用photokit框架所遇到的问题,希望有遇到该问题的朋友能够和我一起探讨,如果能有解决办法,也希望可以给予我一些帮助。
在最新的photokit框架中上文已经提到获取图片的block会调用多次,而在我们进行项目测试时,发现在1000张图片之内,本身是很快并且很高效的。
这里贴上demo地址https://github.com/Archerry/WMHAlbumSelectOC.git(之前会崩溃的已经替换掉了,现在换上最近重构优化的)
上面是OC版本,这个是swift版本github.com/Archerry/swift-photokit