iOS:<Photos/Photos.h>获取相册视频以及图片

因为项目的需求,要捕获相册中的视频与图片,之前也对之尚未做过什么探讨,仅知道iOS8.0后,苹果推出了新的相册管理的包,那么正好,现在可以看看这个框架了,也知道AlAssetLibrary,使用的话倒是没有详细应用过,因此也不与PhotoKit进行对比了。

temp.gif

类的介绍:

//PHCachingImageManager(PHImageManager的抽象) 处理图像的整个加载过程的缓存要加载大量资源的缩略图时可以使用该类的startCachingImage...预先将图像加载到内存中 ,使用时注意size要一致

成员介绍

先挑明自己踩到的坑..

1、 首次调用相册权限的为难:仅会获取相应的权限提示 而不会响应方法
    //每次访问相册都会调用这个handler  检查改app的授权情况
    //PHPhotoLibrary 
    [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
        if (status == PHAuthorizationStatusAuthorized) {
          //code
        }
    }];
2、获取所有图片(注意不能在胶卷中获取图片,因为胶卷中的图片包含了video的显示图)
    [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil];//这样获取
    也可以使用PHFetchOptions中的谓词过滤获取
    PHFetchOptions *fetchResoultOption = [[PHFetchOptions alloc] init];
    fetchResoultOption.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:false]];
    fetchResoultOption.predicate = [NSPredicate predicateWithFormat:@"mediaType = %d",PHAssetMediaTypeImage];
3、使用PHImageManager请求时的回调同步or异步时、block回调次数的问题
4、回调得出的图片size的问题: 由3个参数决定
     在ShowAlbumViewController 中观察
     在PHImageContentModeAspectFill 下  图片size 有一个分水岭  {125,125}   {126,126}
     当imageOptions.resizeMode = PHImageRequestOptionsResizeModeExact;
     时: 设置size 小于{125,125}时,你得到的图片size 将会是设置的1/2
     而在PHImageContentModeAspectFit 分水岭  {120,120}   {121,121}
5、回调中info字典key消失的问题:
      简单地说,就是你如果是自定义的size,且返回的图片的size小于源图片的size 那么你将会得不到图片的相对路径等部分key
6、显示的相册名字不是中文:在info.plist 中设置
      Localized resources can be mixed   YES
      本地资源的适配
7、This app has crashed because it attempted to access privacy-sensitive data
    without a usage description.  
    The app's Info.plist must contain an NSPhotoLibraryUsageDescription key 
    with a string value explaining to the user how the app uses this data.
    本app因未得到使用说明就直接企图访问私人数据而导致崩溃。
    app想要访问这些私人数据就得在info.plist增加一个以NSPhotoLibraryUsageDescription为键,以字符串为值的键值对。=

一、先来一个简单的练习吧:获取本机系统所有的图片

在collectionView中

- (void)getAllPhotosFromAlbum {//配置简单 ,但是参数却是比价多且
    self.options= [[PHImageRequestOptions alloc] init];//请求选项设置
    self.options.resizeMode=PHImageRequestOptionsResizeModeExact;
//resizeMode  自定义设置图片的大小 枚举类型*
// PHImageRequestOptionsResizeMode:*
//PHImageRequestOptionsResizeModeNone = 0, //保持原size
//PHImageRequestOptionsResizeModeFast, //高效、但不保证图片的size为自定义size
//PHImageRequestOptionsResizeModeExact, //严格按照自定义size

   self.options.synchronous=YES;   //YES 一定是同步    NO不一定是异步
  imageOptions.resizeMode = PHImageRequestOptionsResizeModeExact;
        /*
     PHImageRequestOptionsResizeModeNone // 不调整大小
     PHImageRequestOptionsResizeModeFast // 由系统去安排,情况不定:有时你设置的size比较低,会根据你设的size,有时又会比
     PHImageRequestOptionsResizeModeExact// 保证精确到自定义size :此处精确的前提得用PHImageContentModeAspectFill
     */
    
    //simageOptions.version = PHImageRequestOptionsVersionCurrent;//版本 iOS8.0之后出的图片编辑extension,可以根据次枚举获取原图或者是经编辑过的图片,
    /*PHImageRequestOptionsVersion:
     PHImageRequestOptionsVersionCurrent = 0, //当前的(编辑过?经过编辑的图:原图)
     PHImageRequestOptionsVersionUnadjusted, //经过编辑的图
     PHImageRequestOptionsVersionOriginal    //原始图片
     */
    
    //    imageOptions.networkAccessAllowed = YES;//用于开启iClould中下载图片
    //    imageOptions.progressHandler   //iClould下载进度的回调
    
    imageOptions.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;//在imageOptions.synchronous = NO的情况下最终决定是否是异步

//容器类
  (PHFetchResult *) self.assets= [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil];
    //此处option是对获取得到对 Collection 的配置  我只是把它设为nil了 可以这样使用
   /*
//例如按资源的创建时间进行一个排序
         PHFetchOptions *options = [[PHFetchOptions alloc] init];
//    NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:nil ascending:YES];
         options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]]; 
//其中:key是PHAsset类的属性   这是一个kvc
         PHFetchResult *assetsFetchResults = [PHAsset fetchAssetsWithOptions:options];
    */
  [self.containView.collectionView reloadData];
}

- (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView cellForItemAtIndexPath:(NSIndexPath*)indexPath {
    AlbumCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:ALBUMCELLID forIndexPath:indexPath];
//cell.backgroundColor= [UIColor redColor];
    CGSize size =CGSizeMake(50,50);//自定义image size变化情况颇为复杂 下面由说到

    //返回一个 PHImageRequestID,在异步请求时可以根据这个ID去取消请求,同步就没办法了..
    [[PHImageManager defaultManager] requestImageForAsset:self.assets[indexPath.row] targetSize:size contentMode:PHImageContentModeDefault options:self.options resultHandler:^(UIImage*_Nullable result,NSDictionary*_Nullable info) {
 /*
         最终产生图片的size是有   imageOptions.resizeMode(即PHImageRequestOptions) 以及 PHImageContentMode  决定的,当然也有我们设定的size
         优先级而言 
         PHImageRequestOptions > PHImageContentMode
         */
        //这个handler 并非在主线程上执行,所以如果有UI的更新操作就得手动添加到主线程中
//       dispatch_async(dispatch_get_main_queue(), ^{ //update UI  });

#pragma If -[PHImageRequestOptions isSynchronous] returns NO (or options is nil), resultHandler may be called 1 or more times. .........异步就这个回调会调用1或多次....
#pragma If -[PHImageRequestOptions isSynchronous] returns YES, resultHandler will be called exactly once同步就1次.
//一开始本来打算是利用数据吧所有的相片先存起来的.但是发现同步会卡UI  但是异步又会被回调多次,我的数组都变成double了...只好把任务方法方法cellforItem中
    cell.photoImageView.contentMode = UIViewContentModeScaleAspectFit;
    cell.photoImageView.image = result;
}];
  return cell;
}
/*注意这个info字典   有时这个info甚至为null   慎用
     里面的key是比较奇怪的
     尽量不要用里面的key
     因为这个key 会变动: 当我们最终获取到的图片的size的高/宽  没有一个达到能原有的图片size的高/宽时
     部分key 会消失  如 PHImageFileSandboxExtensionTokenKey , PHImageFileURLKey
     */
    /*
     在PHImageContentModeAspectFill 下  图片size 有一个分水岭  {125,125}   {126,126}
     当imageOptions.resizeMode = PHImageRequestOptionsResizeModeExact;
     时: 设置size 小于{125,125}时,你得到的图片size 将会是设置的1/2
     
     而在PHImageContentModeAspectFit 分水岭  {120,120}   {121,121}   
     至于为什么会这样???- -   可能苹果考虑性能吧
     */

注意到上面这个resultHandler,返回一个UIImage,以及一个NSDictionary,图片就不多说了,关键是这个info实在是诡异...

这就引起了我的关注:size和key的关系

围绕着size的大小这个key竟然是不一样的............
我把图也打印出来了// 条件: size = {300,300}


本来是猜测我们设定的这个size比原图小的时候,会产生一张新的图片,而这张图片本地资源是不存在的,所以少了部分的key,

但是现在就尴尬了,看第二个image的原图,分明也是比{300,300}小的,为什么也没了部分key了呢,不太懂....

大家不要误会,第一张图片的原图是肯定大于{300,300} 的,为什么显示不是{300,300},因为我使用处理图片的模式为PHImageContentModeAspectFit,所以显示下来的并非我们{300,300}而是保留原图的比例,大家可以动手去试一试

而且这个size其实是像素:
CGSizeMake(self.assets[indexPath.row].pixelWidth,self.assets[indexPath.row].pixelHeight);
或者设定一个肯定比原图大的size就能获取到原图了....当然,后者是不靠谱的...

或许是这个size出的问题吧,会导致如果我要根据这个PHimageFileKey 获取本地的图片的时候就因为某部分的image因为size的原因缺少这个key使得找不到这张图,使得我app出现bug....不过这个方法真的挺不安全的,建议是把返回的result 那张image 写进tmp里面 再使用吧。。。。

再者就是异步请求次数跟size的关系

当我的self.options.synchronous=NO;//就是一个异步请求的过程(后来发现其实异步请求并不由options的synchronous属性决定)
而这个PHImageRequestOptions 可以根据它的一个属性deliveryMode 去控制异步请求的次数
PHImageRequestOptionsDeliveryMode:
PHImageRequestOptionsDeliveryModeOpportunistic//根据我self.options.synchronous判断返回结果是一个抑或多个
PHImageRequestOptionsDeliveryModeHighQualityFormat //制定的同步返回一个结果,返回的图片质量是比我们设定的size会好一点(实际上与PHImageRequestOptions的resizeMode枚举相关)
PHImageRequestOptionsDeliveryModeFastFormat//仅返回一次,效率较高之余获得的图质量不太好

 我这边配合的resizeMode模式为强制自定义的图片大小,即:
self.options.resizeMode=PHImageRequestOptionsResizeModeExact;//严格按照自定义图片大小的加载模式

如果不是这个枚举的话,返回的PHImageRequestOptionsDeliveryModeOpportunistic第一次返回的缩略图,以及PHImageRequestOptionsDeliveryModeFastFormat所返回的缩略图最小默认是{60,60},
PHImageRequestOptionsResizeModeExact则可以随意设置

值得注意的是,当我们选择的是PHImageRequestOptionsDeliveryModeOpportunistic时,返回的次数是跟size有关系的,你设定的的size 太小的话仅会回调一次,大的话,首次返回的是一个小的缩略图(这个缩略图最大是{60,60},具体值根据比例),二次回调才会得到我们想要的图片

总而言之,图片的真实size跟resizeMode和PHImageRequestOptionsDeliveryMode以及我们设定的size都有关联吧,具体应用的时候就要多试试几次,观察自己真实所需吧...

接下来的是我要找的是视频......问题又出现了,这个PhotoKit有提供查找视频的方式么...
然后我把这修改了一下。。。改成了找Video 的元数据   哈哈哈哈哈哈哈
self.assets= [PHAsset fetchAssetsWithMediaType:**PHAssetMediaTypeVideo** options:nil];

但我好像又踩上了自己挖的坑了...



全是图片....不,不是这样的。。。

在回头看看发现有PHImageManager 这个单例提供我们3个方法去找得到Vide 我则选取了其中一个通用的方法

PHFetchResult *assetsResult = [PHAssetfetch AssetsWithMediaType:PHAssetMediaType Videooptions:nil];
PHVideoRequestOptions *options2 = [[PHVideoRequestOptions alloc] init];
options2.deliveryMode=PHVideoRequestOptionsDeliveryModeAutomatic;
for(PHAsset *a in assetsResult) {                       
   [[PHImageManager defaultManager] requestAVAssetForVideo:a options:options2 resultHandler:^(AVAsset*_Nullable asset,
    AVAudioMix*_Nullable audioMix,NSDictionary*_Nullable info) {
    NSLog(@"%@",info);
  }];
}

找到你了....

不过你居然在。。。PHImageFileSandboxExtensionTokenKey。。。这个key里面



看来地址是要用要用截取的了,可以直接输入到finder就能找到这个视频,但是前面的字符串就得让我们手动去取其子字符串只需要拿到video的Path就可以了

很不安全,我真的怕这个key突然又因为什么原因而miss掉了........
然后我看了看asset 的类型 发现它的类型为AVURLAsset,有点意思,看看里面发现了一个是有个URL属性的!而且是asset的相对路径, 好像可以做点什么...

//video路径获取
if (asset && [asset isKindOfClass:[AVURLAsset class]] && [NSString stringWithFormat:@"%@",((AVURLAsset *)asset).URL].length > 0) {
  NSString *videoURLStr = [NSString stringWithFormat:@"%@",((AVURLAsset *)asset).URL];
  videoPath = ((AVURLAsset*)asset).URL.path;
}

二、根据实际需求的部分获取资源

怎么个实际法呢,有时候你对着一大堆图片,然后找啊找,调啊调,还真的不是什么好方法...为什么就不能在我分好的类别中选取呢!!!!

好的,就下来就说这种情况,大家在开头都一定看到那幅,资源与资源集合的一个关系图...

获取所有用户自定义的相册:1\2\3分别是我创建的相册,以下代码能捕获到,自己创建的的相册的内容


捕获系统相册中的图片/video


解释一下

PHFetchResult*smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];

这个获取资源集合的方法 需要填写两个枚举的类型,大概翻译了下,有错误的大家可以提一下,我会非常感激的

demo地址
参考文章:
1、照片框架:https://objccn.io/issue-21-4/#PhotoKit-Object-Model%5D(http://objccn.io/issue-21-4/#PhotoKit-Object-Model
2、iOS 开发之照片框架详解:http://kayosite.com/ios-development-and-detail-of-photo-framework.html

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

推荐阅读更多精彩内容

  • 一、 PhotoKit的变量: PHAdjustmentData: When a user edits an as...
    漓汐Arthur阅读 1,647评论 1 3
  • 昨天一天下午还真是个种查,各种搜索,然后各种技术群,各种问,(没人鸟我),其实我是有这个能力的,怎么就一上...
    梦随兴飞阅读 25,061评论 7 18
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,599评论 18 139
  • 在太多的地方搭建过博客了,重csdn到自己免费空间搭建wordpress,其次到基于otcopress在githu...
    好迪阅读 459评论 0 1
  • 那一次的四目相对 让我听到了花开的声音 如今的我 正坐在没有你的陌生教室里 忆着你给我的感觉 怀念 只能怀念
    二楠_nnn阅读 242评论 0 0