iOS 获取系统相册内视频与图片(AssetsLibrary篇)

好些天没写点东西了,最近公司要做新项目,有点小忙。不想我的坚持就此中断,我把我前些天研究的东西拿出来给大家看看。
这次整理的是AssetsLibrary和PhotoKit的使用。本人处女座,有点强迫症,之前写的项目里用的是AssetsLibrary写的调取相册内的媒体文件,但是Xcode总是报警告错误,虽然能够编译并展示效果,但是十几个警告错误挂在那,心里总不是滋味,所以我就研究了一下AssetLibrary和PhotoKit。
在 iOS 8 出现之前,开发者只能使用 AssetsLibrary 框架来访问设备的照片库,这是一个有点跟不上 iOS 应用发展步伐以及代码设计原则但确实强大的框架,考虑到 iOS7 仍占有不少的渗透率,因此 AssetsLibrary 也是本文重点介绍的部分。而在 iOS8 出现之后,苹果提供了一个名为 PhotoKit 的框架,一个可以让应用更好地与设备照片库对接的框架。

一、AssetsLibrary 组成##

AssetsLibrary 的组成比较符合照片库本身的组成,照片库中的完整照片库对象、相册、相片都能在 AssetsLibrary 中找到一一对应的组成,这使到 AssetsLibrary 的使用变得直观而方便。想要了解AssetsLibrary得从它的类开始。

AssetsLibrary: 代表整个设备中的资源库(照片库),通过 AssetsLibrary 可以获取和包括设备中的照片和视频

  • ALAssetsGroup: 映射照片库中的一个相册,通过 ALAssetsGroup 可以获取某个相册的信息,相 册下的资源,同时也可以对某个相册添加资源。
  • ALAsset: 映射照片库中的一个照片或视频,通过 ALAsset 可以获取某个照片或视频的详细信息, 或者保存照片和视频。
  • ALAssetRepresentation: ALAssetRepresentation 是对 ALAsset 的封装(但不是其子类),可以更方便地获取 ALAsset 中的资源信息,每个 ALAsset 都有至少有一个 ALAssetRepresentation 对象,可以通过 defaultRepresentation 获取。而例如使用系统相机应用拍摄的 RAW + JPEG 照片,则会有两个 ALAssetRepresentation,一个封装了照片的 RAW 信息,另一个则封装了照片的 JPEG 信息。

二、AssetsLibrary 的基本使用##

AssetsLibrary 的功能很多,基本可以分为对资源的获取/保存两个部分,保存的部分相对简单,API 也比较少,因此这里不作详细介绍。获取资源的 API 则比较丰富了,一个常见的使用大量 AssetsLibrary API 的例子就是图片选择器(ALAsset Picker)。要制作一个图片选择器,思路应该是获取照片库-列出所有相册-展示相册中的所有图片-预览图片大图。
首先是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];
    // 展示提示语
}

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

_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!\n");
}];

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

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

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

_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 参数,这个参数表示资源的索引。一般来说,展示资源列表都会使用缩略图(result.thumbnail),因此即使资源很多,遍历资源的速度也会相当快。但如果确实需要加载资源的高清图或者其他耗时的处理,则可以利用上面的 index 参数和 stop 参数做一个分段拉取资源。例如:

NSUInteger _targetIndex; // index 目标值,拉取资源直到这个值就手工停止拉取
NSUInteger _currentIndex; // 当前 index,每次拉取资源时从这个值开始
 
_targetIndex = 50;
_currentIndex = 0;
 
- (void)loadAssetWithAssetsGroup:(assetsGroup *)assetsGroup {
    [assetsGroup enumerateAssetsAtIndexes:[NSIndexSet indexSetWithIndex:_currentIndex] options:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
        _currentIndex = index;
        if (index > _targetIndex) {
            // 拉取资源的索引如果比目标值大,则停止拉取
            *stop = YES;
        } else {
            if (result) {
                [_imagesAssetArray addObject:result];
            } else {
                // result 为 nil,即遍历相片或视频完毕
            }
        }
    }];
}// 之前拉取的数据已经显示完毕,需要展示新数据,重新调用 loadAssetWithAssetsGroup 方法,并根据需要更新 _targetIndex 的值

最后一步是获取图片详细信息,例如:

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

对于一个 ALAssetRepresentation,里面包含了图片的多个版本。最常用的是 fullResolutionImage 和 fullScreenImage。fullResolutionImage 是图片的原图,通过 fullResolutionImage 获取的图片没有任何处理,包括通过系统相册中“编辑”功能处理后的信息也没有被包含其中,因此需要展示“编辑”功能处理后的信息,使用 fullResolutionImage 就比较不方便,另外 fullResolutionImage 的拉取也会比较慢,在多张 fullResolutionImage 中切换时能明显感觉到图片的加载过程。因此这里建议获取图片的 fullScreenImage,它是图片的全屏图版本,这个版本包含了通过系统相册中“编辑”功能处理后的信息,同时也是一张缩略图,但图片的失真很少,缺点是图片的尺寸是一个适应屏幕大小的版本,因此展示图片时需要作出额外处理,但考虑到加载速度非常快的原因(在多张图片之间切换感受不到图片加载耗时),仍建议使用 fullScreenImage。

系统相册的处理过程大概也是如上,可以看出,在整个过程中并没有使用到图片的 fullResolutionImage,从相册列表展示到最终查看资源,都是使用缩略图,这也是 iOS 相册加载快的一个重要原因。

这里我整理一个demo,欢迎大家给予指正。demo链接如下:https://github.com/Snoopy008/ChooseAlbumFile

结语##

由于时间有限,我还是将PhotoKit的内容放在下一篇。敬请期待。。。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • 写在前面 在手机APP日益增加的前提下,如何更好的提升用户的交互体验似乎成为衡量一个APP重要指标。上述的感悟源于...
    Jack_lin阅读 6,221评论 12 62
  • 图片视频管理 AssetsLibrary 在ios8之前 ,只能使用AssetsLibrary 来访...
    苏永茂阅读 1,368评论 0 10
  • 由于前段时间,需要完成一个跟相册的需求,所以阅读了一些与图片有关的文章,和使用了一些相关的第三方库。 在 iOS ...
    CoderLocus阅读 57,099评论 76 55
  • AssetsLibrary的详细使用 AssetsLibrary的组成 AssetsLibrary的组成和iPho...
    FlowerKanZhe阅读 6,377评论 7 13
  • “助推”是一种深含价值观和目标,同时充分考虑到如何调动资源、制定有效流程、使目标得以实现、使价值观得以坚守的“硬球...
    gyl58365阅读 1,432评论 0 1