iOS开发AssetsLibrary的介绍

一.概要

在iOS8之前,开发者只能使用AssetsLibrary框架来访问设备的照片和视频.而在iOS8之后,苹果提供了PhotoKit框架.一个可以让应用更好地与设备照片库对接的框架

二.AssetsLibrary组成介绍

   AssetsLibrary中的的类都是以AL开头的

1.ALAssetsLibrary:代表整个设备中的照片和视频,通过ALAssetsLibrary可以获取和包括设备中的照片和视频

2.ALAssetsGroup:映射照片库中的一个相册,通过ALAssetsGroup可以获取某个相册的信息,相册下的照片和视频,同时也可以对某个相册添加资源

3.ALAsset:映射相册中的一个照片或者视频,通过ALAsset可以获取某个照片或者视频的详细信息,获取保存照片和视频

4.ALAssetRepresentation:ALAssetRepresentation是对ALAsset的封装(但不是其子类),可以更方便地获取ALAsset中的资源信息,每个ALAsset都有至少一个ALAssetRepresentation对象,可以通过default<Representation获取.而例如使用系统相机拍摄的RAW+JPEG照片,则会有两个ALAssetRepresentation对象,一个封装了照片的RAW信息,另一个则封装了照片的JPEG信息

5.ALAssetsFilter:相当于过滤器,有三个方法,allPhotos:获取相册中所有的照片.allVideos:获取相册中所有的视频.allAssets:获取照片库中的相册,通过ALAssetsGroup类中的setAssetsFilter来调用

三.AssetsLibrary的基本使用

1.首先是要检测App是否有照片操作授权:

NSString *tipTextWhenNoPhotosAuthorization; // 提示语
// 获取当前应用对照片的访问授权状态
ALAuthorizationStatus authorizationStatus = [ALAssetsLibrary authorizationStatus];
// 如果没有获取访问授权,或者访问授权状态已经被明确禁止,则显示提示语,引导用户开启授权
if (authorizationStatus == ALAuthorizationStatusRestricted || authorizationStatus == ALAuthorizationStatusDenied) {
    NSDictionary *mainInfoDictionary = [[NSBundle mainBundle] infoDictionary];
    NSString *appName = [mainInfoDictionary objectForKey:@"CFBundleDisplayName"];
    tipTextWhenNoPhotosAuthorization = [NSString stringWithFormat:@"请在设备的\"设置-隐私-照片\"选项中,允许%@访问你的手机相册", appName];
    // 展示提示语
}

2.如果已经获取授权,则可以获取相册列表:

_assetsLibrary = [[ALAssetsLibrary alloc] init];
_albumsArray = [[NSMutableArray alloc] init];
[_assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
    if (group) {
        [group setAssetsFilter:[ALAssetsFilter allPhotos]];
        if (group.numberOfAssets > 0) {
            // 把相册储存到数组中,方便后面展示相册时使用
            [_albumsArray addObject:group];
        }
    } else {
        if ([_albumsArray count] > 0) {
            // 把所有的相册储存完毕,可以展示相册列表
        } else {
            // 没有任何有资源的相册,输出提示
        }
    }
} failureBlock:^(NSError *error) {
    NSLog(@"Asset group not found!");
}];

上面的代码中,遍历出所有的相册列表,并把相册中资源数不为空的相册ALAssetGroup对象的引用贮存到一个数组中.这里需要强调几点:

  • iOS中允许相册为空,即相册中没有任何资源,如果不希望获取空相册,则需要向上面的代码中那样手动过滤
  • ALAssetGroup有一个setAssetsFilter的方法,可以传入一个过滤器,控制只获取相册中的照片或只获取视频.一旦设置过滤,ALAssetGroup中资源列表和资源数量的获取也会被自动更新
  • 整个ALAssetsLibrary中对相册、资源的获取和保存都是使用异步处理(Asynchronous),这是考虑到资源文件体积相当比较大.例如上面的遍历相册操作,相册的结果使用block输出,如果相册遍历完毕,则最后一次输出的block中的group参数值为nil.而stop参数则是用于手动停止遍历,只要把*stop设置为YES,则会停止下一次的遍历

3.现在,已经可以获取相册了,接下来是获取相册中资源:

_imagesAssetArray = [[NSMutableArray alloc] init];
[assetsGroup enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
    if (result) {
        [_imagesAssetArray addObject:result];
    } else {
        // result 为 nil,即遍历相片或视频完毕,可以展示资源列表
    }
}];

跟遍历相册的过程类似,遍历相片也是使用一系列的异步方法,其中上面的方法所输出的block中,除了result参数表示资源信息,stop用于手工停止遍历外,还提供一个index参数,这个参数表示资源的索引

4.最后一步是获取图片详细信息:

// 获取资源图片的详细资源信息,其中 imageAsset 是某个资源的 ALAsset 对象
ALAssetRepresentation *representation = [imageAsset defaultRepresentation];
// 获取资源图片的 fullScreenImage
UIImage *contentImage = [UIImage imageWithCGImage:[representation fullScreenImage]];

5.保存照片到相册:

ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init];  
[assetsLibrary writeImageDataToSavedPhotosAlbum:imageData metadata:nil completionBlock:^(NSURL *assetURL, NSError *error) {  
             
       }]; 

四.AssetsLibrary的坑点:

1.AssetsLibrary实例需要强应用:

   一般我们可以申明一个属性@property (nonatomic, strong) ALAssetsLibrary *assetsLibray;然后我们使用懒加载的方式初始化这个属性,实例一个 AssetsLibrary 后,如上面所示,我们可以通过一系列枚举方法获取到需要的相册和资源,并把其储存到数组中,方便用于展示.但是,当我们把这些获取到的相册和资源储存到数组时,实际上只是在数组中储存了这些相册和资源在 AssetsLibrary 中的引用(指针),因而无论把相册和资源储存数组后如何利用这些数据,都首先需要确保 AssetsLibrary 没有被 ARC 释放,否则把数据从数组中取出来时,会发现对应的引用数据已经丢失(参见下图.这一点较为容易被忽略,因此建议在使用 AssetsLibrary 的 viewController 中,把 AssetsLibrary 作为一个强持有的 property 或私有变量,避免在枚举出 AssetsLibrary 中所需要的数据后,AssetsLibrary 就被 ARC 释放了.

2.AssetsLibrary遵循写入优先原则:

   写入优先也就是说,在利用AssetsLibrary读取资源的过程中,有任何其它的进程(不一定是同一个App)在保存资源时,就会收到ALAssetsLibraryChangedNotification通知,让用户自行中断读取操作.最常见的就是读取fullResolutionImage时,用进程写入,由于读取fullResolutionImage耗时较长,很容易就会exception

3.开启Photo Stream容易导致exception:

   本质上,这跟上面的 AssetsLibrary 遵循写入优先原则是同一个问题.如果用户开启了共享照片流(Photo Stream),共享照片流会以 mstreamd 的方式"偷偷"执行,当有人把相片写入 Camera Roll 时,它就会自动保存到 Photo Stream Album 中,如果用户刚好在读取,那就跟上面说的一样产生 exception 了.由于共享照片流是用户决定是否要开启的,所以开发者无法改变,但是可以通过下面的接口在需要保护的时刻关闭监听共享照片流产生的频繁通知信息.

[ALAssetsLibrary disableSharedPhotoStreamsSupport];

参考资料:
objc中国 - 照片框架
AssetsLibrary Framework Reference


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值