美文网首页iOS精品文章InterviewiOS点点滴滴
iOS开发之AssetsLibrary与photokit总结

iOS开发之AssetsLibrary与photokit总结

作者: Archer_bling | 来源:发表于2017-01-26 19:36 被阅读1818次

    首先声明,本人为iOS初级开发菜鸟一枚,现开始总结工作中遇到的问题以及对工作的相关技术进行相关总结,希望能够给予一些刚开始接触iOS的新人部分作用,同时最重要的是希望能够将我所遇到的问题以及技术同大家进行分享,希望可以得到大神帮助。demo下载地址在最下方。

    最近由于公司需求,本人需要进行一个自定义相册的封装,在过去的一个月中,先后使用了苹果的AssetsLibrary框架以及photokit框架,两种不同的框架使用下来感觉各有千秋,在这里和大家分享并希望能够得到大神的帮助。

    一、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地址github.com/Archerry/PhotoKitDemo

    上面是OC版本,这个是swift版本github.com/Archerry/swift-photokit

    相关文章

      网友评论

      • 64e627e6c487:亲 我用photokit读取出照片然后显示在我自己建的界面 然后选择单张照片读取信息,这样会比ALAssetLibrary读取到的信息少很多,例如{“GPS”}的信息是移到了PHAsset对象的location里了,但是其他信息也被阉割了好多,{“TIFF”}信息只剩下一个了。能看一下是为什么吗
      • a7c6cec64788:大神 选择单张图片 用哪个 比较合适
        Archer_bling:@a7c6cec64788 我没有做裁剪,不过裁剪不是用photokit了,这个只是帮助你拿系统资源的框架,裁剪的话你需要看一下上下文
        a7c6cec64788:@Archerry 我这个有单张 裁剪 photokit 有支持这个的么
        Archer_bling:单张的现在也最好用photokit吧,版本更新越高,photokit的效率越高,我写的这个也支持单张的,传值就好
      • FengxinLi:非常感谢!networkAccessAllowed = YES; 这个也可以下载的我看最新版的qq在每张图上面还有个标志 点击下载还有进度条,那个是怎么监听的呢?
        FengxinLi:@Archerry 非常感谢!
        Archer_bling:这个就是我刚才和你说的网络下载的还有一个progressHandler的block回调,这个block 里会返回图像下载的进度,图像的信息,出错信息,通过这些信息你可以自定制下载进度的这些操作了
      • FengxinLi:亲demo可以在ios11上面运行吗?怎么我运行崩溃了?
        FengxinLi:@Archerry 你相册里面可以展示上传到iCloud里面的相册不?可以选择还没下载到本地的iCloud图片不?
        FengxinLi:@Archerry NSAssert1(NO, @"Fetch collection not PHCollection: %@", collection); 我崩溃到这了
        Archer_bling:@FengxinLi 可以运行啊,我刚才下载了试了一下可以的啊
      • 溪浣双鲤:写的深刻 支持一下
        Archer_bling:@溪浣双鲤 过后更新我会赋上demo,你可以看一下,现在已经优化好了
        溪浣双鲤:@Archerry 之前没接触过这个, 表示不知道该怎么下手 , 看了之后自己又找了个demo瞬间明白了
        Archer_bling:@溪浣双鲤 谢谢:grin:

      本文标题:iOS开发之AssetsLibrary与photokit总结

      本文链接:https://www.haomeiwen.com/subject/jaoxittx.html