Photo Kit Tips

iOS8出现了Photo Kit,相信很多同学早已开始使用.随着iOS11的到来,对于大部分App来说,iOS7应该渐渐的退出历史舞台.如果想要重构代码,相信相册是一个优先级较高的模块.

如何使用Photo Kit,有太多的资料,这里就不在赘述.这里提供一些tips,记录下一些需要注意的地方.

API版本

注意API的版本.虽然Photo Kit是iOS8的产物,但是仍然由部分API是出现在iOS9上.例如PHFetchOptionsfetchLimit.

API特性差异

API也在不同的iOS版本中迭代.其中造成了特性的差异.例如在获取图片的exif信息时,我们通常使用一条API:

- (PHContentEditingInputRequestID)requestContentEditingInputWithOptions:(nullable PHContentEditingInputRequestOptions *)options completionHandler:(void (^)(PHContentEditingInput *__nullable contentEditingInput, NSDictionary *info))completionHandler PHOTOS_AVAILABLE_IOS_TVOS(8_0, 10_0);

在回调中,返回一个PHContentEditingInput,我们可以根据其fullSizeImageURL属性创建一个CIImage,CIImageproperties即为exif信息.

但是这条API在iOS10和10以前是有差异的.根据文档描述:

In iOS 10.0, tvOS 10.0, and later, Photos always calls this block on the main
queue. In earlier releases, Photos calls this block on an arbitrary serial queue
—if your block needs to update the UI, dispatch that work to the main queue.

所以会引申出一个问题:
在兼容iOS7的时代,我们通常使用ALAssetmetaData作为exif信息.这是同步的.但如果切换成Photo kit,取exif信息则是异步的.并且该API并没有同步选项.那么此时有2种选择:

  1. 修改代码逻辑,切换成异步.
  2. 修改获取exif方法为同步.

如果选择方案1,那么OK.没有任何影响.如果采用方案2,那么通常采用dispatch_semaphore_t来进行处理.

事实上,如此处理的话,在iOS10以前都是OK的.但是iOS10以及以后会出现死锁的现象.至于原因,也就是API的描述了.iOS10会主动切换到主线程.那为毛切换到主线程就会死锁?这可以去详细了解下GCD的原理啦!

所以..还是选择方案1吧..

变更处理

变更处理算是相册相关处理比价复杂的一个地方.

Photo Kit处理的看似很复杂,有很多个很奇怪的东西.例如:PHChange,PHFetchResultChangeDetails等.

但是仔细看看,实际上是非常容易理解的.

需要注意的是文档的一些说明:

when updating your app’s interface, apply removals before insertions, changes,
and moves

这里提醒了处理顺序.

然后变更可能会多次调用,即使你仅仅删除了一张照片或者增加一张照片.多次调用的原因是changed变更这个东东.可能系统会认为你更新了某些照片.

所以合理的刷新策略是关键.如果收到了变更通知就刷新相关列表,可能会造成性能的浪费.

最后一个是,一般来讲,照片的顺序是依据创建时间或者修改时间.所以通常在处理insert变更的时候,无论修改时间还是创建时间,都是最新的.那么可能直接就插入到照片数组的0的index了.

实际上还要考虑到用户可能修改了时间,照片中存在着未来时间这样一种情况.

exif

ALLibrary中,提供了一条api:

- (void)writeImageToSavedPhotosAlbum:(CGImageRef)imageRef metadata:(NSDictionary *)metadata completionBlock:(ALAssetsLibraryWriteImageCompletionBlock)completionBlock NS_DEPRECATED_IOS(4_1, 9_0, "Use creationRequestForAssetFromImage: on PHAssetChangeRequest from the Photos framework to create a new asset instead");

这条api可以连同图片和exif信息一起写入.

而Photo Kit并没有提供类似的方法.那么需要自己处理.

可以这样将exif信息写入image:

- (NSData *)appendExif:(NSDictionary *)exif toImage:(UIImage *)image {
    NSData *data = UIImageJPEGRepresentation(image, 1);
    CFDataRef cfData = CFBridgingRetain(data);
    CGImageSourceRef imageSource = CGImageSourceCreateWithData(cfData, nil);
    CFBridgingRelease(cfData);
    NSDictionary *defaultAttributes = (__bridge NSDictionary *)CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL);
    NSMutableDictionary *attributes = defaultAttributes.mutableCopy;
    [attributes addEntriesFromDictionary:exif];
    
    NSMutableData *output = [NSMutableData new];
    CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)output, kUTTypeJPEG, 1, NULL);
    CGImageDestinationAddImageFromSource(imageDestination, imageSource, 0, (__bridge CFDictionaryRef)attributes);
    CGImageDestinationFinalize(imageDestination);
    CFRelease(imageDestination);
    return output;
}

但是这返回的是NSData,如果直接转换成UIImage,那么相关的exif信息将会丢失.
所以需要做的是,将这个data写入到文件.然后使用以下方法创建request,最终保存.

PHAssetChangeRequest *request = [PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:url];
照片

Photo Kit中取照片需要传入一个size.并没有ALAsset中的thumb等内置尺寸.不过可以简单的实验出对应的size.

而这里的size是绝对size(像素).例如:size传入(100,100),那么无论在何种屏幕上,都是100*100的尺寸.有可能会在plus这种3x的屏幕上造成模糊.

所以更合理的做法是size乘以一个scale:

[UIScreen mainScreen].scale
缓存

官方提供了一个PHCachingImageManager用于缓存.方法很简单,只有一个start,两个stop方法.

苹果也提供了一个在scrollview中使用缓存的算法.核心思路是:

根据当前位置,计算出一个更大的区域.将更大的区域中的cell/collectionView cell的index path计算出来.然后缓存这个更大的区域中的数据.当然,也会计算区域的差值,用于取消缓存.

类似于一个预加载+缓存的思路.

不过对于快速滑动的列表,预加载对于加载速度的提升起不了太大的作用.只有缓存是有用的.如果想要提升加载速度(非缓存).适当的减少获取图片的size是一个效果提升比较明显的途径.甚至可以针对中低端机型进行处理.合理的策略,能够做到更好的用户体验.

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

推荐阅读更多精彩内容