前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS 开发实践:iOS照片API的那些坑

iOS 开发实践:iOS照片API的那些坑

作者头像
天天P图攻城狮
发布2018-07-09 18:54:26
2.8K0
发布2018-07-09 18:54:26
举报
文章被收录于专栏:天天P图攻城狮

作者简介:keyishen(沈珂轶) 天天P图 iOS 工程师

在和图片打交道的那些日子里,遇到过不少图片相关的诡异问题。 在这里不会具体对照片API做介绍,而只会对其中的一些坑做一些总结。

1.不要完全相信系统API

当我们的程序有crash,但是通常我们的crash上报系统会上报自己app的crashlog,例如以下crashlog:

------------------------------------------------------------------------------------------------

由于是很偶现的crash,反复检查代码也没有发现什么疑点。还好在测试手机上后来发现了同一时间的另一个crashlog,如下:

------------------------------------------------------------------------------------------------

------------------------------------------------------------------------------------------------

原来在同一时间,系统负责AssetsLibrary功能的进程/System/Library/Frameworks/AssetsLibrary.framework/Support/assetsd crash了。从而导致了-[ALAsset valueForProperty:] 的调用始终卡在了那里。

系统的图片相关的操作主要是通过assetsd进程来实现的。

在对系统相册做一系列复杂操作后,有时会把系统assetsd进程搞挂,如果这时再回到app内调用Photos相关的API,就会出现异常现象,比如卡住,或者crash。这时可以看看手机里同一时刻之前是否有系统asset进程的crash堆栈。

我们目前的crash上报系统,往往无法定位到这张情况的问题。对于这种需要查看关联crash的情况就需要对系统的API也要合理地质疑。

2.不推荐自己写选图控件

对于选图没有太高要求的app,建议使用系统的选图控件UIImagePickerController,这样开发快捷便利,但是在我看来最大的优点在于这样做未来的维护成本会很小,尤其是可以在未来几乎第一时间享受到系统选图控件的新功能和新特性。

当然缺点是可调整的东西少,无法做个性化的定制,例如,不能控制UI,也很难做多图选择的扩展。

不过最不推荐的是在UIImagePickerController上面做UI的修改,这样虽然能够满足一时需求,但是却是为未来埋下了不少隐患,维护成本很高。

在iOS 10,如果用UIImagePickerController的话,还需要规避一个系统API会crash的坑。

在推出了3D touch之后,系统的UIImagePickerController在长按图片时会有偶现的crash。建议通过在UICollectionViewController的category里增加2个消息处理,来规避这个问题。具体增加的category如下:

3.支持的最低系统版本

苹果官方推荐始终只支持最新的2个大系统,就今天而言(2018.7)理论上我们应该只用支持iOS 10和iOS 11。然而国内的大环境,使得我们通常还需要从iOS 7,或者iOS 8开始支持。

对于图片类App来说,有一条很重要的分水岭,那就是iOS 8.1。

iOS 8开启了Photos.framework的新时代,而iOS 7及以下开发者只能使用AssetsLibrary的API。

然而可能是由于iOS 8推出匆忙,在iOS 8.0.x系统上,PHAsset的fetchAssetsWithMediaType: 和 fetchAssetsWithOptions:方法会返回iTunes同步的照片,以及iCloud照片流上的照片,所以如果你的照片被传到照片流上去后,通过这两个API返回的相册列表里会有两份相同的照片。

好在在iOS 8.1上苹果修改了这一API的行为,不再返回iTunes照片,以及照片流照片,使得Photos.framework从整个版本开始才真正意义上是可用的了。

对于小于iOS 8.1的系统都需要同时AssetsLibrary和Photos.framework两套图片API,对于非图片重度的app来说工作量不小。所以,推荐直接从iOS 9开始支持,如果不行的话,推荐至少从iOS 8.1开始支持(当然更合理的是从8.4开始支持,这样升级不到iOS 9的手机也有机会使用上)。

4.iCloud的坑

如果使用Photos.framework,那避不开的问题就是要支持iCloud上的照片。

为了推广苹果自己的iCloud的服务,并且拯救那些16GB手机的空间,苹果会将照片上传到iCloud,并且在本地只保存一份低清的照片。

4.1判断是否在iCloud上

我们APP在选图时需要判断本地是否存有原图。

Photos.framework提供了requestImageDataForAsset来获取图片的info。

Info的内容大致是这样的:

Printing description of info:

{

    PHImageResultDeliveredImageFormatKey = 9999;

    PHImageResultIsDegradedKey = 0;

    PHImageResultIsInCloudKey = 1;

    PHImageResultIsPlaceholderKey = 0;

    PHImageResultRequestIDKey = 54;

    PHImageResultWantedImageFormatKey = 9999;

}

理论上,info中的PHImageResultIsInCloudKey字段会告诉APP图片是否在iCloud上。

然而实际测试下来,该系统API有一个坑。在以上option的设置下,即使刚刚成功下载了这张图片,返回的info还是PHImageResultIsInCloudKey=1。

所以如果自己成功下载过图片后,还需要自己另外记忆下载的状态,在一定时间内,如果刚刚成功下载了图片,就应当要无视PHImageResultIsInCloudKey字段的状态,因为该字段的更新有滞后。

4.2判断iCloud API的卡死

在iOS 10系统上,还有一个新的坑,那就是用requestImageDataForAsset这个API会有一定概率出现永远不执行回调。

根据对在线用户的性能监控,我们发现这甚至是造成我们app卡顿的最大原因。通过对场景的重现我们发现,当这个API出现不回调bug时,各大主流app也几乎无一幸免,基本都卡在了那里。

所以为了解决这个问题,在调用requestImageDataForAsset的时候切忌放在主线程同步地做,并且需要给它一个超时时间,不让它无限制的执行。

5.正确获取缩略图

- (PHImageRequestID)requestImageForAsset:(PHAsset *)asset targetSize:(CGSize)targetSize contentMode:(PHImageContentMode)contentMode options:(nullable PHImageRequestOptions *)options resultHandler:(void (^)(UIImage *__nullable result, NSDictionary *__nullable info))resultHandler;

通过以上API,我们可以获取到各种尺寸的图片。虽然灵活性比之前AssetsLibrary的获取缩略图API高很多,但是方便程度差了不少,更多的灵活性带了的问题也不少。

这里涉及到一个系统API的坑requestImageForAsset这个API在某些targetSize下返回为空。

例如,在测试设备iPad Air(iOS 9.3.1)上,

如果targetSize=CGSizeMake(x, x),

当contentMode=PHImageContentModeAspectFill时,

且1<=x<=64 or 81<=x<=257时,

resultHandler返回的result image为nil。

当contentMode=PHImageContentModeAspectFit时,

且121<=x<=385时,

resultHandler返回的result image为nil。

在调用时需要多试试各个系统以及机型的适配性,尽量避开这些取值范围。

6.删除图片的API

在低于iOS 8的系统上,AssetsLibrary没有明确地提供删除图片的接口。

但事实上很多图片类APP通过修改图片的接口起到删除图片的作用,即通过ALAsset的接口直接删除图片。

但是当base sdk到了iOS 10之后,我们发现之前能用的接口现在在iOS 8.1及以上系统,会出现成功回调不执行的问题。

解决方法也很简单,就是直接使用Photos.framework提供的接口来删除图片:

附录:

https://objccn.io/issue-21-4/

http://stackoverflow.com/questions/25883005/avoiding-duplicates-when-getting-pictures-with-phasset

文章后记: 天天P图是由腾讯公司开发的业内领先的图像处理,相机美拍的APP。欢迎扫码或搜索关注我们的微信公众号:“天天P图攻城狮”,那上面将陆续公开分享我们的技术实践,期待一起交流学习!

加入我们: 天天P图技术团队长期招聘: (1) 图像处理算法工程师 (2) Android / iOS 开发工程师 期待对我们感兴趣或者有推荐的技术牛人加入我们(base 上海)!联系方式:ttpic_dev@qq.com

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-07-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 天天P图攻城狮 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
应用性能监控
应用性能监控(Application Performance Management,APM)是一款应用性能管理平台,基于实时多语言应用探针全量采集技术,为您提供分布式性能分析和故障自检能力。APM 协助您在复杂的业务系统里快速定位性能问题,降低 MTTR(平均故障恢复时间),实时了解并追踪应用性能,提升用户体验。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档