AssetsLibrary的详细使用

AssetsLibrary的详细使用

AssetsLibrary的组成

AssetsLibrary的组成和iPhone中相册的实际组成十分的类似,AssetsLibrary库中的类结构对应相册中的相册应用、相册、相片或视频,具体的类组成如下:
1.AssetsLibrary:代表iPhone中的资源库(包含所有的photo、video),可以这么认为,AssetsLibrary就带包iPhone中的相册应用。可以通过AssetsLibrary获取所有的AssetsGroup。同时可以向资源库中添加相册;

2.AssetsGroup:映射照片库(AssetsLibrary)中的一个相册,同过AssetsGroup可以获取相册相应的信息,同时获取可以通过相册(AssetsGroup)获取相册下的资源,同时也在当前相册下保存资源;

3.ALAsset:对应相册中的一张照片或者视频,ALAsset包含了照片或视频的详细信息,可以通过ALAsset获取缩略图。另一方面可以使用ALAsset的实例方法保存照片或视频;

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

AssetsLibrary一般用于定制一个图片选择器,图片选择器相应的可以实现多选、自定义界面。相应的思路应该是:

1.实例化照片库,列出所有相册
2.展示相册中的所有图片
3.对选图片或则点击图片预览大图。

因此AssetsLibrary的讲解大体通过上面的过程来详细的讲解。

1. 实例化AssetsLibrary && AssetsLibrary类的详解

1>实例化AssetsLibrary

实例化很简单,就普通的alloc init方法,如果你还想精简那就用new吧

ALAssetsLibrary * library = [[ALAssetsLibrary alloc] init];

2>遍历照片库(ALAssetsLibrary)中的所有相册(AssetsGroup)

    self.groups = [NSMutableArray array];
    // 遍历相册
    [library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
        if (group) { // 遍历相册还未结束
            // 设置过滤器
            [group setAssetsFilter:[ALAssetsFilter allPhotos]];
            if (group.numberOfAssets) {
                [self.groups addObject:group];
            }
        } else { // 遍历结束(当group为空的时候就意味着结束)
            if (self.groups.count) {
            // 如果相册个数不为零,则可以在此处开始遍历相册了
            //[self enumerateAssets];
            } else {
                NSLog(@"没有相册列表");
            }
        }
    } failureBlock:^(NSError *error) {
        NSLog(@"遍历失败");
    }];

上面的代码遍历出了所有的相册,并把相册中资源数量不为空的相册对象(AssetsGroup)的应用存储到了一个数组中。
需要注意的是:
1.ALAssetsLibrary需要相册为空,即相册中没有任何资源。如果你不想把为空的相册保存到数组中,可以通过AssetsGroup的numberOfAssets属性判断相册是否为空,为空则不保存。
2.ALAssetsGroup有一个过滤器的实例方法:setAssetsFilter,通过此方法传入的枚举值,可以设置只获取相册中的photo或者video。同时设置后,或更新AssetsGroup对应的numberOfAssets。
3.在AssetsLibrary框架之下,所有的遍历操作都是异步(Asynchronous)执行的。因为用户的资源库、相册可能很大,这种条件之下,异步遍历不至于堵塞主线程。另外,当遍历对应的block中的输出结果参数为空(nil),则意味遍历结束。当然,通过给定的stop参数,你也可以在满足某种条件下手动的停止遍历。

2. 遍历相册(AssetsGroup)中的所有相片或视频(Asset)

AssetsGroup提供了三种遍历方式:
1.- (void)enumerateAssetsUsingBlock:
2.- (void)enumerateAssetsWithOptions:usingBlock:
3.- (void)enumerateAssetsAtIndexes:options:usingBlock:

遍历相册:

- (void)enumerateAssets {
    NSMutableArray * assets = [NSMutableArray new];
    for (ALAssetsGroup * group in self.groups) {
        
        /*
         // 遍历所有的相片
        [group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
            if (result) { // 遍历未结束
                [assets addObject:result];
            } else { // result 为nil,遍历结束
                
            }
        }];
         */
        
        // 遍历指定的相片
        NSInteger fromIndex = 0; // 重指定的index开始遍历
        NSInteger toIndex =5; // 指定最后一张遍历的index
        [group enumerateAssetsAtIndexes:[NSIndexSet indexSetWithIndex:toIndex] options:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
            if (index > toIndex) { // 已经遍历到指定的最后一张照片
                *stop = YES; // 停止遍历
            } else {
                if (result) {
                    // 存储相片
                    [assets addObject:result];
                } else { // 遍历结束
                    // 展示图片
                    //[self showPhotoWith:result];
                }
            }
        }];
    }
}

遍历相册(ALAssetsGroup)中的照片(ALAsset)和遍历资源库(ALAssetsLibrary)中的相册过程十分的类似,不过遍历相册中的照片更加的灵活,可以通过enumerateAssetsUsingBlock: 遍历所有的照片,同时可以通过enumerateAssetsAtIndexes:options:usingBlock:方法遍历指定index的照片。这正如上面代码中段注释类是遍历所有的照片,段注释下面遍历指定index一样。

ALAssetsGroup的详解
ALAssetsGroup代表的是一个相册,这个概念在上面已经说得够详细了,就不介绍了。在这里主要说说ALAssetsGroup类中的方法与属性的含义和用法。

- (void)showALAssetsGroupInfo:(ALAssetsGroup *)assetsGroup {
    
    // 是否可编辑,即相册是否可以通过代码添加相片
    BOOL editable = assetsGroup.editable;
    
    // 添加一个ALAsset到当前相册,前提editable = YES,
    [assetsGroup addAsset:nil];
    
    /**
     + (ALAssetsFilter *)allPhotos; // 获取Photo
     + (ALAssetsFilter *)allVideos; // 获取Video
     + (ALAssetsFilter *)allAssets; // 获取Photo还有video
     */
    // 设置过滤器
    [assetsGroup setAssetsFilter:[ALAssetsFilter allPhotos]];
    
    // 当前过滤器下的ALAsset数量
    NSInteger number = assetsGroup.numberOfAssets;
    
    /**
     NSString *const ALAssetsGroupPropertyName; // Group的名称
     NSString *const ALAssetsGroupPropertyType; // Group类型(ALAssetsGroupType)
     NSString *const ALAssetsGroupPropertyPersistentID;
     NSString *const ALAssetsGroupPropertyURL; // 唯一表示这个Group的URL,可以通过URL在资源库中获取对应的Group,用于唯一标识这个group
     */
    // 通过Property获取ALAssetsGroup对应的信息
    NSLog(@"%@", [assetsGroup valueForProperty:ALAssetsGroupPropertyName]);
    NSLog(@"%@", [assetsGroup valueForProperty:ALAssetsGroupPropertyType]);
    NSLog(@"%@", [assetsGroup valueForProperty:ALAssetsGroupPropertyPersistentID]);
    NSLog(@"%@", [assetsGroup valueForProperty:ALAssetsGroupPropertyURL]);
    
    // 获取相册封面
    [assetsGroup posterImage];
    
}

3 获取相片(ALAsset)中的详细内容

在这里需要详细的说明一下,所有的ALAsset所对应的照片信息存在与ALAsset中的ALAssetRepresentation对象中,通过ALAssetRepresentation可以获取这个ALAsset对应的原图、修改过后的图。而通过ALAsset可以获取ALAsset对应的缩略图。另外需要说明的是,一个ALAsset可能对应多个ALAssetRepresentation,原因在与相册取图的时候可能抓取多种不同格式的图片,例如:RAW和JPEG格式的图片,此时ALAsset就存在两个ALAssetRepresentation,此时就可以通过不同的ALAssetRepresentation获取不同格式的原图、修改后的全屏图。

获取原图、全屏图:

- (void)showPhotoWith:(ALAsset *)asset {
    // 获取ALAsset对应的ALAssetRepresentation
    ALAssetRepresentation * representation = [asset defaultRepresentation];
    
    NSLog(@"%@", representation.url); // 图片URL
    NSLog(@"%@", NSStringFromCGSize(representation.dimensions)); // 图片尺寸
    NSLog(@"%lld", representation.size); // 数据字节
    NSLog(@"%@", representation.UTI); // Uniform Type Identifier : 统一类型标识符(表示图片或视频的类型)
    NSLog(@"%@", representation.filename); // 在相册中的文件名
    NSLog(@"%@", representation.metadata); // 元数据(一些设备相关的信息,比如使用的相机)
    NSLog(@"%lf", representation.scale); // 缩放比例
    NSLog(@"%ld", representation.orientation); // 方向
    /**
     fullScreenImage : 返回当前设备尺寸大小的图片,编辑后的图片
     fullResolutionImage : 原图,没有编辑的图片
     */
    // 获取原图
    UIImage * image = [UIImage imageWithCGImage:[representation fullScreenImage] scale:1.0 orientation:UIImageOrientationDownMirrored];
    self.imageView.image = image;
}

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

ALAsset详解:

- (void)showALAssetInfoWith:(ALAsset *)asset {
    /**
     NSString *const ALAssetPropertyType;
     NSString *const ALAssetPropertyLocation;
     NSString *const ALAssetPropertyDuration;
     NSString *const ALAssetPropertyOrientation;
     NSString *const ALAssetPropertyDate;
     NSString *const ALAssetPropertyRepresentations;
     NSString *const ALAssetPropertyURLs;
     NSString *const ALAssetPropertyAssetURL;
     */
    NSLog(@"%@", [asset valueForProperty:ALAssetPropertyType]); // 这个type表示这个是photo还是video
    NSLog(@"%@", [asset valueForProperty:ALAssetPropertyLocation]); // 拍摄的地点
    NSLog(@"%@", [asset valueForProperty:ALAssetPropertyDuration]); // 视频的时长
    NSLog(@"%@", [asset valueForProperty:ALAssetPropertyOrientation]); // 照片的方向
    NSLog(@"%@", [asset valueForProperty:ALAssetPropertyDate]); // 照片的拍摄时间
    NSLog(@"%@", [asset valueForProperty:ALAssetPropertyRepresentations]);
    NSLog(@"%@", [asset valueForProperty:ALAssetPropertyURLs]); //
    NSLog(@"%@", [asset valueForProperty:ALAssetPropertyAssetURL]);

    [asset thumbnail]; // 返回缩略图
    [asset aspectRatioThumbnail]; // 等比例缩略图
    [asset representationForUTI:@"public.jpeg"]; // 通过统一类型标识获取ALAssetRepresentation
    
    // ALAsset 还具有更改ALAsset中的元数据能力
    // ALAsset 的实例方法能保存Photo、video到相册
}

4. AssetsLibrary 的坑点

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

推荐阅读更多精彩内容

  • 写在前面 在手机APP日益增加的前提下,如何更好的提升用户的交互体验似乎成为衡量一个APP重要指标。上述的感悟源于...
    Jack_lin阅读 6,221评论 12 62
  • 由于前段时间,需要完成一个跟相册的需求,所以阅读了一些与图片有关的文章,和使用了一些相关的第三方库。 在 iOS ...
    CoderLocus阅读 57,096评论 76 55
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,600评论 18 139
  • 人的旅途就像一列开往世界尽头的列车,人来人往,熙熙攘攘。在成长的路上,我们会得到很多东西:那些新奇的世界和未知的未...
    Lu羊羊阅读 807评论 1 2
  • 疲惫的心 拖着千疮百孔的身躯 在回忆的高速路上 奔驰向前 无畏前路漫漫 风景依旧 伊人 已不现
    清宵雨淅淅阅读 264评论 0 0