Photos.framework是iOS8后苹果推出的一套替代AssetsLibrary.framework获取相册资源的原生库,至于AL库,欢迎大家给博文iOS开发——简单实现图片多选功能(AssetsLibrary.framework篇)提出宝贵的意见。

楼主大部分都是查看官方开发文档进行探索的(当然,实在不明白了也会请求google 的 0.0 )。这里就说一下个人的看法吧,相比AL库,Photos的开发文档显然更像是目前我们接触的ObjC语言(如果不信,可以对比一下AL库和Photos库的开发文档)。初次接触这个库的时候可能会感觉比较乱,毕竟类的数量比AL库多了好多,但在熟悉大体逻辑之后,就会发现它的分工比AL更加明确,并且使用起来要比AL灵活的多。

提醒一下,要使用相册资源库的时候,为了适配一下将来的iOS10,不要忘记在info.plist文件中加入NSPhotoLibraryUsageDescription这个描述字段啊,更多的权限坑请关注一下博文 iOS开发——iOS 10 由于权限问题导致崩溃的那些坑

ObjC- 全代码 : https://github.com/RITL/RITLImagePickerDemo

2017-01-22 更新

Swift - 全代码:https://github.com/RITL/Swift-RITLImagePickerDemo

Swift-Demo 重写完不久,可能Swift的编程思想还不是领略的很好,但楼主会继续努力。

Objc-Demo的用法如下:

RITLPhotoNavigationViewModel * viewModel = [RITLPhotoNavigationViewModel new];__weak typeof(self) weakSelf = self;//    设置需要图片剪切的大小,不设置为图片的原比例大小
//    viewModel.imageSize = _assetSize;viewModel.RITLBridgeGetImageBlock = ^(NSArray <UIImage *> * images){//获得图片__strong typeof(weakSelf) strongSelf = weakSelf;strongSelf.assets = images;[strongSelf.collectionView reloadData];};viewModel.RITLBridgeGetImageDataBlock = ^(NSArray <NSData *> * datas){//可以进行数据上传操作..};RITLPhotoNavigationViewController * viewController = [RITLPhotoNavigationViewController photosViewModelInstance:viewModel];[self presentViewController:viewController animated:true completion:^{}];

Swift- Demo用法

//获得控制器
let viewController : RITLPhotoNavigationViewController = RITLPhotoNavigationViewController()//设置viewModel属性
let viewModel = viewController.viewModel// 获得图片
viewModel.completeUsingImage = {(images) in}// 获得资源的data数据
viewModel.completeUsingData = {(datas) in//coding for data ex: uploading..print("data = \(datas)")
}self.present(viewController, animated: true) {}

话说的有点多了,下面就谈谈个人对Photos的理解,这里只记录一下Photos.framework中类的使用与理解,真正的实现多选功能请前去上面的链接下载demo查看,多谢指正:

类逻辑

研究一个库或者框架,总体逻辑一定是要缕清的,下面就是个人对photos的理解,有点多,分类一下吧:

资源类

  • PHPhotoLibrary 是一个资源库。能够获取相册权限以及对相册的操作,与AL不同,它不能获取资源对象哦.
  • PHFetchResult 是一个结果集,一个泛型类。通过方法获取到的相册或者资源组就是被封装成该类返回.
  • PHAssetCollection 是一个资源集合对象。其实它就是一个相册的概念,可通过类方法获得想要的相册集合,继承自PHCollection.
  • PHCollectionList 是一个资源集合列表对象。刚接触时以为它是存放PHCollection对象的集合,后来才知道,如果想要通过地点以及时间分组的话,请使用这个类替代PHAssetCollection吧,用法与PHAssetCollection类似,同样是继承自PHCollection.
  • PHAsset 是一个独立的资源对象。可以通过类方法对PHCollection对象进行遍历,获得存放Asset对象的结果集,可以直接获得资源的规格数据,若想获得图片以及原图等资源,需要配合PHImageManager对象,继承自PHObject.

工具类

  • PHFetchOptions 一个遍历配置类。一般情况下,当存在遍历方法的时候就存在这个类型的参数,里面含有谓词、遍历顺序等属性,可以通过设置这些属性,完成不同的遍历.
  • PHImageManager 是一个负责渲染资源的类。比如获得PHAsset对象的原图等操作需要使用该类.
  • PHCachingImageManager 继承自PHImageManager,可以对请求的资源对象进行缓存,这样再次获取时就不需要重新渲染,在加快获取速度的同时也降低了CPU的压力,这里最好对缓存的PHImageRequestID进行一下记录,防止同一资源被无限缓存的尴尬.
  • PHImageRequestOptions 是一个资源请求的配置类。通常在使用PHImageManager对某个资源进行请求时都会存在此类型的参数,可以在请求资源时对该对象进行设置,获得想要的结果,比如原图..

请求类

  • 请求类不能独立使用,要想发挥作用,需要与PHPhotoLibrary对象配合使用.
  • PHAssetCollectionChangeRequest 集合变化请求类,负责对PHAssetCollection对象的操作
  • PHCollectionListChangeRequest 集合变化请求类,负责PHCollectionList对象的操作
  • PHAssetChangeRequest 资源变化请求类,负责PHAsset对象的操作

类库中的类及其属性方法:

这里提到的都是代码中用到的属性和方法,如果只是为了多图选择,那么以下的方法应该是够用的,不够的话可以Command+单击进入开发文档查看即可。

PHPhotoLibrary_照片库

基础方法

我觉得下面的方法应该都懂,毕竟每个涉及到权限的库都会存在下面三个方法的.

//获得单例对象
+ (PHPhotoLibrary *)sharedPhotoLibrary;
//获得相册权限
+ (PHAuthorizationStatus)authorizationStatus;
//请求权限
+ (void)requestAuthorization:(void(^)(PHAuthorizationStatus status))handler;

操作相册

之前说请求类不能独自使用,需要配合PHPhotoLibrary对象,为什么这么说呢,是因为在使用请求类的时候必须使用下面两个方法其中之一,下面是开发文档的一句话:

/*表示请求只能通过下面两种方法的block进行创建和使用,所有的ChangeRequest类上面都会存在这句话,当然类名肯定不一样的.*/
PHAssetCollectionChangeRequest can only be created or used within a -[PHPhotoLibrary performChanges:]
or -[PHPhotoLibrary performChangesAndWait:] block.//异步执行change的变化请求
- (void)performChanges:(dispatch_block_t)changeBlock completionHandler:(nullable void(^)(BOOL success, NSError *__nullable error))completionHandler;//同步执行change的请求变化
- (BOOL)performChangesAndWait:(dispatch_block_t)changeBlock error:(NSError *__autoreleasing *)error;

其实我感觉只看上面的两个方法感觉会比较抽象,那么就拿出Demo中的两段小源码举个例子,相信这样就比较好理解了.

新建相册

///新建一个名字叫做title的相册
-(void)addCustomGroupWithTitle:(NSString *)titlecompletionHandler:(void (^)(void))successBlockfailture:(void (^)(NSString * _Nonnull))failtureBlock
{[self.photoLibaray performChanges:^{//创建一个创建相册的请求[PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:title];}completionHandler:^(BOOL success, NSError * _Nullable error) {if (success == true)//成功{successBlock();return ;}//失败failtureBlock(error.localizedDescription);}];
}

向相册里面添加图片

///向collection中添加图片
-(void)addCustomAsset:(UIImage *)imagecollection:(PHAssetCollection *)collectioncompletionHandler:(void (^)(void))successBlockfailture:(void (^)(NSString * _Nonnull))failtureBlock
{//执行变化请求[self.photoLibaray performChanges:^{//如果相册允许操作if([collection canPerformEditOperation:PHCollectionEditOperationAddContent]){//创建资源请求对象PHAssetChangeRequest * assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];//创建相册请求对象PHAssetCollectionChangeRequest * groupChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:collection];//向相册中添加资源[groupChangeRequest addAssets:@[assetChangeRequest.placeholderForCreatedAsset]];}}completionHandler:^(BOOL success, NSError * _Nullable error) {if (success == true)//成功{successBlock();return;}//失败failtureBlock(error.localizedDescription);}];
}//这里不止能够通过图片对象创建,还存在如下两种创建方法
+ (nullable instancetype)creationRequestForAssetFromImageAtFileURL:(NSURL *)fileURL;//通过图片所在的路径url进行创建+ (nullable instancetype)creationRequestForAssetFromVideoAtFileURL:(NSURL *)fileURL;//通过视频所在的路径url进行创建

PHAssetCollection_资源集合对象

  • 常用属性
//组的标题,比如Camera Roll(胶卷相册)
@property (nonatomic, strong, readonly, nullable) NSString *localizedTitle;//资源组的类型,比如是智能相册,普通相册还是外界创建的相册
PHAssetCollectionType assetCollectionType;typedef NS_ENUM(NSInteger, PHAssetCollectionType) {PHAssetCollectionTypeAlbum      = 1, //传统相册PHAssetCollectionTypeSmartAlbum = 2, //智能相册PHAssetCollectionTypeMoment     = 3, //自定义创建的相册
} NS_ENUM_AVAILABLE_IOS(8_0);//具体的子类型,比如是智能相册的自拍还是喜爱等,这个枚举类太多,就不进行粘贴了.
PHAssetCollectionSubtype assetCollectionSubtype;//资源组中资源的大约数量,不一定准,如果想要确切的,获得PHFetchResult对象取count即可
NSUInteger estimatedAssetCount;//最早的一张图片存在相册的时间
NSDate *startDate;//最近的一张图片存在相册的时间
NSDate *endDate;
  • 获得具体资源的方法,基本都是通过类方法进行获取,这样就降低了PhotosLibrary对象复杂度。
//判断是否能够进行编辑,如果是进行修改请求,最好通过这个方法来判断是下
- (BOOL)canPerformEditOperation:(PHCollectionEditOperation)anOperation;//获得智能分组,比如胶卷相册,最近添加,自拍等
PHFetchResult * smartGroups = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbumsubtype:PHAssetCollectionSubtypeAlbumRegularoptions:nil];//获得我们自定义创建的相册组,比如有QQ的手机应该都会有QQ这个相册,那么通过该方法就可以获取的到
+ (PHFetchResult<PHCollection *> *)fetchTopLevelUserCollectionsWithOptions:(nullable PHFetchOptions *)options;

如果PHFetchResult觉得用起来不是很爽的话,可以将其包装成数组来进行下一步的操作,Demo中就是将其打包成数组来进行操作的:

@implementation PHFetchResult (NSArray)//将PHFetchResult对象转成NSArray对象
-(void)transToArrayComplete:(void (^)(NSArray<PHAssetCollection *> * _Nonnull, PHFetchResult * _Nonnull))arrayObject
{__weak typeof(self) weakSelf = self;NSMutableArray *  array = [NSMutableArray arrayWithCapacity:0];if (self.count == 0){arrayObject([array mutableCopy],weakSelf);array = nil;return;}[self enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {[array addObject:obj];//如果遍历完毕,进行回调if (idx == self.count - 1){arrayObject([array mutableCopy],weakSelf);}}];
}@end

PHAsset_资源对象

  • 常用属性
//资源媒体的类型
PHAssetMediaType mediaType;typedef NS_ENUM(NSInteger, PHAssetMediaType) {PHAssetMediaTypeUnknown = 0,  //未知类型PHAssetMediaTypeImage   = 1,  //图片类型PHAssetMediaTypeVideo   = 2,  //视频类型PHAssetMediaTypeAudio   = 3,  //音频类型
} NS_ENUM_AVAILABLE_IOS(8_0);//资源美图的子类型,比如如果资源是图片,那么它是全景还是HDR,如果是iOS9,还能知道他是屏幕截图还是live图片,枚举有点多,也不再次粘贴了.
PHAssetMediaSubtype mediaSubtypes;//资源的像素宽
NSUInteger pixelWidth;//资源的像素高
NSUInteger pixelHeight;//资源的创建日期
NSDate *creationDate;//资源的最近一次修改的时间
NSDate *modificationDate;//资源拍摄的地点
CLLocation *location;//如果是音频或者视频,它的持续时间
NSTimeInterval duration;//它是否被隐藏
BOOL hidden;//它是否是喜爱的
BOOL favorite;
  • 常用搭配使用方法
//请求图片,将想要获取Image实体的资源,裁剪的大小以及方式进行获取图片
//如果想要原图,设置PHImageRequestOptions对象的deliveryMode属性为PHImageRequestOptionsDeliveryModeHighQualityFormat即可
[[PHImageManager defaultManager]requestImageForAsset:assettargetSize:sizecontentMode:PHImageContentModeAspectFilloptions:optionresultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {//通过block回传图片,并将部分信息存在于info字典中,并且该方法的返回值可以在info字典中找到
}];
//请求数据,获取资源的Data对象,可以用来计算资源的大小。
//这样可以避免UIImage->Data导致内存以及CPU瞬间激增
[[PHImageManager defaultManager]requestImageDataForAsset:assetoptions:optionresultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {//在block里面获取图片的各种信息
}];
//这里最好存在一个标位置或者其他方法标志一下,避免每次都要缓存导致的卡顿以及CPU卡死
[((PHCachingImageManager *)[PHCachingImageManager defaultManager])startCachingImagesForAssets:@[copy_self]targetSize:newSizecontentMode:PHImageContentModeAspectFilloptions:nil];

PHFetchResult_结果集合

表示乍一看,是不是和数组很相似呀.

  • 属性
//当前集合的数量
NSUInteger count;//获得index位置的对象
- (ObjectType)objectAtIndex:(NSUInteger)index;//是否包含对象
- (BOOL)containsObject:(ObjectType)anObject;//对象的索引
- (NSUInteger)indexOfObject:(ObjectType)anObject;//第一个对象
ObjectType firstObject;//最后一个对象
ObjectType lastObject;
  • 遍历方法,应该也是获取集合内部数据的唯一方法了.
/*使用Block进行枚举遍历,stop控制是否停止,每次获得数据都会执行一次回调*/
- (void)enumerateObjectsUsingBlock:(void (^)(ObjectType obj, NSUInteger idx, BOOL *stop))block;/*根据枚举类型进行枚举,比如正序还是倒序*/
- (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (^)(ObjectType obj, NSUInteger idx, BOOL *stop))block;/*枚举特定区间并按照响应枚举类型进行遍历*/
- (void)enumerateObjectsAtIndexes:(NSIndexSet *)s options:(NSEnumerationOptions)opts usingBlock:(void (^)(ObjectType obj, NSUInteger idx, BOOL *stop))block;

相册发生变化

使用PHPhotoLibrary对象注册观察者,当然,不要在dealloc或者特定的地方注销观察者啊,与KVO相同.

//注册观察者
- (void)registerChangeObserver:(id<PHPhotoLibraryChangeObserver>)observer;//注销观察者
- (void)unregisterChangeObserver:(id<PHPhotoLibraryChangeObserver>)observer;

PHPhotoLibraryChangeObserver协议方法

//This callback is invoked on an arbitrary serial queue.
//If you need this to be handled on a specific queue,
//you should redispatch appropriately.//这个回调是在一个随意的线程中被唤起,如果需要在一个特定的线程中处理,应该在合适的地方重新唤起
//(翻译可能不太准确,如果需要更新,一般情况需要在主线程,这个应该都懂得.)
- (void)photoLibraryDidChange:(PHChange *)changeInstance;

实例

具体用法如下:

首先需要查看是否发生了变化,如果没有变化,那么就返回nil;如果发生了变化,就会返回响应类型的对象:

//PHChange对象的两个方法://获取PHObject对象的变化详情,其实PHAsset和PHCollection都是继承自PHObject的
- (nullable PHObjectChangeDetails *)changeDetailsForObject:(PHObject *)object;
-
//获取结果集的变化详情,和上面一样,如果不存在变化,返回nil
- (nullable PHFetchResultChangeDetails *)changeDetailsForFetchResult:(PHFetchResult *)object;

下面记录一下描述详细变化的类吧:

PHObjectChangeDetails

//PHObject对象变化详情对象
PHObjectChangeDetails.h//变化之前的对象
@property (atomic, strong, readonly) __kindof PHObject *objectBeforeChanges;//变化之后的对象,
@property (atomic, strong, readonly, nullable) __kindof PHObject *objectAfterChanges;//内容是否发生了变化
@property (atomic, readonly) BOOL assetContentChanged;//该对象是否已经删除
@property (atomic, readonly) BOOL objectWasDeleted;@end/*
1、判断一下是否被删除了,如果被删除了,那么请把数据源的该对象也删除了吧,并重新reload一下当前的视图.
2、如果没有被删除,就可以知道是否发生了变化,那么,获取变化后的内容对象并将之前的内容replace一下,刷新视图即可
*/

PHFetchResultChangeDetails

//PHFetchResult对象发生变化的详情类
PHFetchResultChangeDetails.h//变化之前的结果集
@property (atomic, strong, readonly) PHFetchResult *fetchResultBeforeChanges;//变化之后的结果集
@property (atomic, strong, readonly) PHFetchResult *fetchResultAfterChanges;/*
这个变量很有意思:
如果为true,表示集合发生了增删改,那么通过一下面的删除、新增以及更新操作的响应属性或方法进行数据的修改即可。
如果为false,则表示发生了大的改变,不在提供下面那些变化的详情,只能使用fetchResultAfterChanges属性对该属性进行替换即可*/
@property (atomic, assign, readonly) BOOL hasIncrementalChanges;//如果是删除操作,返回删除的位置以及删除的对象
@property (atomic, strong, readonly, nullable) NSIndexSet *removedIndexes;
@property (atomic, strong, readonly) NSArray<__kindof PHObject *> *removedObjects;//如果是新增操作,返回新增的位置以及新增的对象
@property (atomic, strong, readonly, nullable) NSIndexSet *insertedIndexes;
@property (atomic, strong, readonly) NSArray<__kindof PHObject *> *insertedObjects;//如果是更新操作,返回更新的位置以及更新的对象
@property (atomic, strong, readonly, nullable) NSIndexSet *changedIndexes;
@property (atomic, strong, readonly) NSArray<__kindof PHObject *> *changedObjects;/*
1、判断一下hasIncrementalChanges值,如果为false,直接取fetchResultAfterChanges属性进行值的替换
2、如果为true,根据下面的详情数据进行相应操作即可,当然,使用全体替换的方法也是可以的,但是单个操作可以使用动画哦
*/

吐槽

我要开始吐槽啦!其实毕业回学校的时候无聊,想练习一下Swift,研究过这个库,大体的功能与博文Demo的功能差不多,但由于起名太随便,随手删了,没错..删了!(还真是感谢我随手清理垃圾篓的习惯,呵呵….所以大家一定要不忘记备份呀,= = 再就是起名不要太随便啊),这个Demo是趁工作的业余时间写的,目的是加深对Photos库理解的同时不辜负学校的那段时间,不太建议直接拿本文的Demo直接放入工程中使用哦,Demo的目的只是为了学习一下Photos库,尽管对Demo进行了一些内存泄露的处理,但每次还是会有大约1MB多的内存多余占用,这个问题会在之后楼主不断进步的过程中进行修复的

记录完毕3Q

iOS开发------简单实现图片多选功能(Photos.framework篇)相关推荐

  1. 简单实现图片多选功能

    iOS开发------简单实现图片多选功能(Photos.framework篇) 楼主大部分都是查看官方开发文档进行探索的(当然,实在不明白了也会请求google 的 0.0 ).这里就说一下个人的看 ...

  2. iOS开发-简单的图片查看器

    现在你只要拿着手机,不管你Android还是iOS,新闻类的App不可避免都有一个功能就是图片查看,做个专题,查看一下内容,App Store中也有专门针对图片浏览的App,鉴于目前所知有限,无法做到 ...

  3. iOS开发 图片选择器、图片多选功能的实现

    版权声明:本文为博主原创文章,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接. Photos.framework是iOS8后苹果推出的一套替代AssetsLibrary.f ...

  4. IOS开发基础之图片轮播器-12

    IOS开发基础之图片轮播器-12 核心代码 // // ViewController.m // 12-图片轮播器 // // Created by 鲁军 on 2021/2/2. //#import ...

  5. 用jsp实现简单的图片上传功能

    用jsp实现简单的图片上传功能 1 先做一个页面,选择上传的图片 <body><form action="uploadServlet" enctype=" ...

  6. html js简单实现图片轮播功能

    本章记录简单的图片轮播功能,需要html.js和css共同实现1.html文件 <!DOCTYPE html> <html><head><meta chars ...

  7. 最简单的图片预览功能【兼容IE8】

    最简单的图片预览功能[兼容IE8]  将如下代码放入<head></head>中: <html><head> <script type=&quo ...

  8. iOS开发之集成iOS9中的Core Spotlight Framework搜索App的内容

    转载自:  http://www.cnblogs.com/ludashi/p/4867511.html iOS开发之集成iOS9中的Core Spotlight Framework搜索App的内容 S ...

  9. Android开发—简单的图片浏览器

    开发工具:ecplise 图片浏览器:实现简单的图片浏览功能,点击当前图片会自动切换到下一张图片 1.先在布局文件中定义一个简单的线性布局容器 <?xml version="1.0&q ...

最新文章

  1. Timer定时器开发
  2. 五分钟学会HTML5!(二)
  3. vim文本编辑器详解
  4. oracle.jobs中failures,Oracle job详解
  5. python生成器函数_【python】生成器和生成器函数
  6. sun服务器清理内存日志_sun服务器系统日志
  7. sigmoid函数的数值稳定性
  8. 【C语言简单说】七:自定义函数(1)
  9. leetcode 363. 矩形区域不超过 K 的最大数值和
  10. 鸿蒙os开源邀请全球开发者,全场景无缝连接 鸿蒙OS开源邀请全球开发者共助生态发展...
  11. NPM是什么?我们该怎么使用呢
  12. python for informatics_Python for Informatics 第11章 正则表达式一(译)
  13. 【50】了解new和delete的合理替换时机
  14. OpenPLC:符合IEC 61131-3标准的用于网络安全研究的开源工业控制器
  15. linux上的ds命令,使用DS-5 进行Linux应用开发
  16. Photoshop 快捷键大全
  17. ACP知识域三---干系人管理
  18. web期末网站设计大作业 HTML+CSS+JS仿爱奇艺官网影视网站
  19. 云知声终止IPO:持续亏损7.9亿、毛利率低于行业均值、市场份额被指“造假”
  20. 操作系统复习:12.缺页中断以及内存页面置换算法

热门文章

  1. stm32: 串口空闲中断的实现(HAL库)
  2. 【上课课件整理复习】第六章 网页数据的采集(1)
  3. win10动态壁纸怎么设置_酷狗也能设置动态壁纸???
  4. 使用开源激光SLAM方案LIO-SAM运行KITTI数据集,如有用,请评论雷锋
  5. js 获取汉字首拼和全拼和拼音
  6. TP、TN、FP、FN、Recall、Miss Rate、MCC、F1 Score 等指标计算
  7. Excel文档误删的4种恢复方法,1秒就可以还原所有内容,你用过吗
  8. Protel99SE添加泪滴焊盘
  9. Ubuntu下配置FreeRADIUS + PPTP/L2TP + Mysql + daloRADIUS
  10. 世界坐标系,图像坐标系,车体坐标系,雷达坐标系转换