Photo Frameworks之PHAssetCollection、PHCollectionList和PHAsset

该框架在图片app中用来管理图片和音视频文件,用来一部查找和缓存资源或者缩略图、修复内容和在不同设备间同步图片等资源。
先简单的了解一些概念:

  • PHAsset:单个资源
  • PHAssetCollection:PHCollection的子类,单个资源的集合,如相册、时刻等
  • PHCollectionList:PHCollection的子类,集合的集合,如相册文件夹
  • PHPhotoLibrary:类似于总管理,负责注册通知、检查和请求获取权限
  • PHImageManager:按照要求获取制定的图片
  • PHCachingImageManager:PHImageManager的子类
  • PHAssetChangeRequest:编辑相册,增删改查
下面一一做尽可能详尽的说明

*PHCollection

在进行下面的实验之前,先简单的说说该类中的一个方法:
+ (PHFetchResult<PHCollection *> *)fetchTopLevelUserCollectionsWithOptions:(nullable PHFetchOptions *)options;
该方法用来获取处于图片app中根目录下的自己创建的相册(貌似自己创建的本身就在根目录下)

1、PHAssetCollection

一个该实例对象代表一个相册。是PHCollection的子类。
它的所有属性都是只读的,另外有8个类方法,用来获取想要的结果。

  • + (PHFetchResult<PHAssetCollection *> *)fetchAssetCollectionsWithType:(PHAssetCollectionType)type subtype:(PHAssetCollectionSubtype)subtype options:(nullable PHFetchOptions *)options;
    该方法是该类的主要访问方法,主要用于在未知相册的情况下,直接通过type和subtype从相册获取相应的相册。type和subtype如下所示:
typedef NS_ENUM(NSInteger, PHAssetCollectionType) {
 PHAssetCollectionTypeAlbum      = 1,  相册,系统外的
 PHAssetCollectionTypeSmartAlbum = 2,  智能相册,系统自己分配和归纳的
 PHAssetCollectionTypeMoment     = 3,  时刻,系统自动通过时间和地点生成的分组
 } PHOTOS_ENUM_AVAILABLE_IOS_TVOS(8_0, 10_0);
 *
 * typedef NS_ENUM(NSInteger, PHAssetCollectionSubtype) {
 
 // PHAssetCollectionTypeAlbum regular subtypes
 PHAssetCollectionSubtypeAlbumRegular         = 2, // 在iPhone中自己创建的相册
 PHAssetCollectionSubtypeAlbumSyncedEvent     = 3, // 从iPhoto(就是现在的图片app)中导入图片到设备
 PHAssetCollectionSubtypeAlbumSyncedFaces     = 4, // 从图片app中导入的人物照片
 PHAssetCollectionSubtypeAlbumSyncedAlbum     = 5, // 从图片app导入的相册
 PHAssetCollectionSubtypeAlbumImported        = 6, // 从其他的相机或者存储设备导入的相册
 
 // PHAssetCollectionTypeAlbum shared subtypes
 PHAssetCollectionSubtypeAlbumMyPhotoStream   = 100,  // 照片流,照片流和iCloud有关,如果在设置里关闭了iCloud开关,就获取不到了
 PHAssetCollectionSubtypeAlbumCloudShared     = 101,  // iCloud的共享相册,点击照片上的共享tab创建后就能拿到了,但是前提是你要在设置中打开iCloud的共享开关(打开后才能看见共享tab)
 
 // PHAssetCollectionTypeSmartAlbum subtypes
 PHAssetCollectionSubtypeSmartAlbumGeneric    = 200,
 PHAssetCollectionSubtypeSmartAlbumPanoramas  = 201,  // 全景图、全景照片
 PHAssetCollectionSubtypeSmartAlbumVideos     = 202,  // 视频
 PHAssetCollectionSubtypeSmartAlbumFavorites  = 203,  // 标记为喜欢、收藏
 PHAssetCollectionSubtypeSmartAlbumTimelapses = 204,  // 延时拍摄、定时拍摄
 PHAssetCollectionSubtypeSmartAlbumAllHidden  = 205,  // 隐藏的
 PHAssetCollectionSubtypeSmartAlbumRecentlyAdded = 206,  // 最近添加的、近期添加
 PHAssetCollectionSubtypeSmartAlbumBursts     = 207,  // 连拍
 PHAssetCollectionSubtypeSmartAlbumSlomoVideos = 208,  // Slow Motion,高速摄影慢动作(概念不懂)
 PHAssetCollectionSubtypeSmartAlbumUserLibrary = 209,  // 相机胶卷
 PHAssetCollectionSubtypeSmartAlbumSelfPortraits PHOTOS_AVAILABLE_IOS_TVOS(9_0, 10_0) = 210, // 使用前置摄像头拍摄的作品
 PHAssetCollectionSubtypeSmartAlbumScreenshots PHOTOS_AVAILABLE_IOS_TVOS(9_0, 10_0) = 211,  // 屏幕截图
 PHAssetCollectionSubtypeSmartAlbumDepthEffect PHOTOS_AVAILABLE_IOS_TVOS(10_2, 10_1) = 212,  // 在可兼容的设备上使用景深摄像模式拍的照片(概念不懂)
 PHAssetCollectionSubtypeSmartAlbumLivePhotos PHOTOS_AVAILABLE_IOS_TVOS(10_3, 10_2) = 213,  // Live Photo资源
 PHAssetCollectionSubtypeSmartAlbumAnimated PHOTOS_AVAILABLE_IOS_TVOS(11_0, 11_0) = 214,  // 没有解释
 PHAssetCollectionSubtypeSmartAlbumLongExposures PHOTOS_AVAILABLE_IOS_TVOS(11_0, 11_0) = 215,  // 没有解释
 // Used for fetching, if you don't care about the exact subtype
 PHAssetCollectionSubtypeAny = NSIntegerMax
 } PHOTOS_ENUM_AVAILABLE_IOS_TVOS(8_0, 10_0);
  • + (PHFetchResult<PHAssetCollection *> *)fetchAssetCollectionsWithLocalIdentifiers:(NSArray<NSString *> *)identifiers options:(nullable PHFetchOptions *)options;
    通过identifier的数组来查找到相应的资源,不过这里的identifier应使用上面的方法获取到相册后拿到的相册的identifier(根据属性localIdentifier即可获取到),否则会得到意想不到的结果。测试代码如下:
- (IBAction)fetchCollectionWithIdentifier:(id)sender {
    // 先试试用图片的identifier
    NSMutableArray * assetIdentifierArr = [NSMutableArray array];
    NSMutableArray * identifierArr = [NSMutableArray array];
    PHFetchResult<PHAssetCollection *> * result = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
    [result enumerateObjectsUsingBlock:^(PHAssetCollection * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if (obj.localIdentifier.length > 0) {
            NSLog(@"%@--%@", obj.localIdentifier, obj.localizedTitle);
            [identifierArr addObject:obj.localIdentifier];
            PHFetchResult<PHAsset *> * assetResult = [PHAsset fetchAssetsInAssetCollection:obj options:nil];
            PHAsset * asset = assetResult.firstObject;
            [assetIdentifierArr addObject:asset.localIdentifier];
        }
    }];
    // 注意:这里使用的是单个资源的identifier
    PHFetchResult<PHAssetCollection *> * assetIdentifierResult = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:assetIdentifierArr options:nil];
    [assetIdentifierResult enumerateObjectsUsingBlock:^(PHAssetCollection * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if (obj.localIdentifier.length > 0) {
            NSLog(@"%@", obj);
        }
    }];
    NSLog(@"================================");
// 注意:这里使用的是相册的identifier
    PHFetchResult<PHAssetCollection *> * identifierResult = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:identifierArr options:nil];
    [identifierResult enumerateObjectsUsingBlock:^(PHAssetCollection * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if (obj.localIdentifier.length > 0) {
            NSLog(@"%@", obj);
        }
    }];
}

可以先预想一下结果,然后再看下面的截图:
image.png

上面的使用也再一次的证明了identifier一定要使用代码获取到的才行。

  • + (PHFetchResult<PHAssetCollection *> *)fetchAssetCollectionsContainingAsset:(PHAsset *)asset withType:(PHAssetCollectionType)type options:(nullable PHFetchOptions *)options;
    查找包含资源asset的相册
  • + (PHFetchResult<PHAssetCollection *> *)fetchAssetCollectionsWithALAssetGroupURLs:(NSArray<NSURL *> *)assetGroupURLs options:(nullable PHFetchOptions *)options;
    旧版的图片框架和新版框架的交互,不过到了今天,已经基本上不用考虑该方法的调用了。
  • + (PHFetchResult<PHAssetCollection *> *)fetchMomentsInMomentList:(PHCollectionList *)momentList options:(nullable PHFetchOptions *)options;
  • + (PHFetchResult<PHAssetCollection *> *)fetchMomentsWithOptions:(nullable PHFetchOptions *)options;
    上面的两个方法是获取Moment相册的简单方法
  • + (PHAssetCollection *)transientAssetCollectionWithAssets:(NSArray<PHAsset *> *)assets title:(nullable NSString *)title;
  • + (PHAssetCollection *)transientAssetCollectionWithAssetFetchResult:(PHFetchResult<PHAsset *> *)fetchResult title:(nullable NSString *)title;
    利用已知资源创建一个新的集合或者说相册,但是该相册不会被永久存储下来。具体的使用后面再说吧。

2、PHCollectionList

该类用来表示集合的集合。但是我并没有发现怎么创建出该现象。而如果不创建(假如可以创建但是没创建)时,在实际的调用中,得到的结果和预想的也不一样,有些困惑,所以,这一节暂时先放放吧。

3、PHAsset

该类表示具体的资源信息,如宽度、高度、时长、是否是收藏的等等。同上面提到的几个类一样,该类的属性也都是只读的,所以我们主要是用它的方法来获取资源。

  • - (BOOL)canPerformEditOperation:(PHAssetEditOperation)editOperation;
    用来判断该资源是否可以做某些操作,比如增删改查。也从另一个方面暗示了,在对该资源做一些操作之前有必要先做一下判断,这可以省去一些不必要的麻烦。
  • + (PHFetchResult<PHAsset *> *)fetchAssetsInAssetCollection:(PHAssetCollection *)assetCollection options:(nullable PHFetchOptions *)options;
    该方法是从相册中获取单个资源的主要途径:
- (IBAction)useToFetchCollection:(id)sender {
    // 先获取到集合
    PHFetchResult<PHAssetCollection *> * collectionResult = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumFavorites options:nil];
    if (collectionResult.count == 0) {
        return;
    }
    // 遍历集合,获取信息
    [collectionResult enumerateObjectsUsingBlock:^(PHAssetCollection * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        PHFetchResult<PHAsset *> * assetResult = [PHAsset fetchAssetsInAssetCollection:obj options:nil];
        NSLog(@"%@", assetResult);
    }];
}
  • + (PHFetchResult<PHAsset *> *)fetchAssetsWithLocalIdentifiers:(NSArray<NSString *> *)identifiers options:(nullable PHFetchOptions *)options;
    该方法的使用和PHAssetCollection的相同,是个查找功能;如果identifier是隐藏的资源,默认是会被找到的,如果不想找到隐藏的,可以通过options的属性includeHiddenAssets来设置(貌似没什么用)。
  • + (PHFetchResult<PHAsset *> *)fetchAssetsWithBurstIdentifier:(NSString *)burstIdentifier options:(nullable PHFetchOptions *)options;
    根据identifier获取连拍资源,如果传递的identifier不是连拍资源的identifier,即使相册里有匹配的资源,也不会返回。不过苹果官方说明:默认只会获取一些具有代表性的,如果想获取全部的连拍资源,需要在options里做处理。
  • + (PHFetchResult<PHAsset *> *)fetchAssetsWithOptions:(nullable PHFetchOptions *)options;
    在相机胶卷中根据options来获取合适的资源
  • + (PHFetchResult<PHAsset *> *)fetchAssetsWithMediaType:(PHAssetMediaType)mediaType options:(nullable PHFetchOptions *)options;
    在相机胶卷中根据mediaType媒体类型和options获取匹配的资源
  • + (nullable PHFetchResult<PHAsset *> *)fetchKeyAssetsInAssetCollection:(PHAssetCollection *)assetCollection options:(nullable PHFetchOptions *)options;
    获取相册资源的封面图,根据相册类型的不同,返回的资源封面的个数也不同。
    如果是零时的相册,是没有封面的。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容