iOS开发tips-PhotoKit

时间:2019-11-17 16:19:01   收藏:0   阅读:112

概述

技术图片

PhotoKit应该是iOS 8 开始引入为了替代之前ALAssetsLibrary的相册资源访问的标准库,后者在iOS 9开始被弃用。当然相对于ALAssetsLibrary其扩展性更高,api使用起来也更加的强大,但这并非今天讨论的重点,这里主要讨论PhotoKit使用的一些技巧和容易踩的坑。

PHImageManager or Custom

访问相册资源常用的操作还是获取资源,比如获取一张相册的图片,可以通过PHImageManager.default().requestImage(xxx)一个回调就可以了,其实除了简单的图片拉取苹果建议大家使用一个自己维护的PHCachingImageManager(PHImageManager子类)单例,因为从名字可以看出它可以进行资源缓存(具体用法参见:PHCachingImageManager),这个在列表滑动过程中比较有用,因为可以使用startCachingImages(for:targetSize:contentMode:options:)预加载还未显示的资源,在不需要使用的时候调用stopCachingImages(for:targetSize:contentMode:options:)移除缓存,除此之外其实它更多的是使用父类的功能。

关于requestImage(for:targetSize:contentMode:options:resultHandler:)方法其实它的options是更容易让大家使用的时候经常迷糊的地方,因为iOS相册的照片很可能并不在本地而是在iCloud上面存储,本地只有缩略图:

isSynchronousdeliveryModeresizeMode之间的关系(前提是开启网络加载isNetworkAccessAllowed = true):

isSynchronous = true同步加载:此时deliveryMode会被忽略掉,所以只要看resizeMode

isSynchronous = false异步加载:此时要看deliveryMode和resizeMode两者的变化情况

对于是否返回两次结果总结起来对于返回结果只有异步请求在不设置deliveryMode或者deliveryMode = opportunistic 时会发送两次请求。

没错上面的情况如果了解不清楚很容易掉进坑里,一般的情况下只要打开网络,使用默认值即可。但是话说没有网络的情况下是什么情况呢?

无网络情况

上面说了那么多配置那么对于没有网络的情况呢?因为PHImageRequestOptions默认其实就是没有网络的。先看一下下面的请求:

let requestOption = PHImageRequestOptions()
requestOption.resizeMode = .exact
let scale:CGFloat = UIScreen.main.scale
let newSize = CGSize(width: 200.0, height: 200)
PHImageManager.default().requestImage(for: asset, targetSize: newSize, contentMode: .aspectFill, options: requestOption,resultHandler: completeHandler)

首先没有设置isNetworkAccessAllowed属性,那么默认值就是false,这个时候也就是没有任何网络请求,其次resizeMode = .exact也就是请求比较高清的图片。但是一个重要的问题是这个图片可能会是一个低清图片,甚至达不到一个200200的缩略图的预期,有可能特别模糊。
按照前面说的,deliveryMode 没有设置默认是
opportunisticisSynchronous*没有设置默认是false,在异步情况下是 首先这种情况下也会返回两个结果,打印info信息:
第一次:
[AnyHashable("PHImageResultIsDegradedKey"): 1, AnyHashable("PHImageResultRequestIDKey"): 1100]
第二次:
[AnyHashable("PHImageResultIsDegradedKey"): 0, AnyHashable("PHImageErrorKey"): Error Domain=NSCocoaErrorDomain Code=-1 "(null)", AnyHashable("PHImageResultIsInCloudKey"): 1, AnyHashable("PHImageResultRequestIDKey"): 1100]

可以看出第一次是低清图片,第二次是高清,但是此时出错了PHImageResultIsInCloudKey = 1,本地并没有高清图,但是因为无法访问网络去获取就报错了,抛出PHImageErrorKey信息,同时此时返回的image = nil,这样的结果就是只能看到低清图片。因此是否返回清晰照片除了上面说的,还和是否允许网络请求有直接关系。

综上来看除非特殊情况下,请打开网络请求使用异步请求,并且在合适的时机判断是否请求返回两次。

视频获取

对于视频资源的获取和图片还有些不同,因为使用PhotoKit上传视频的过程并不是直接获取到视频路径来做的,当然如果不熟悉这个过程很可能使用下面的方式:

let option = PHVideoRequestOptions()
option.isNetworkAccessAllowed = true
option.version = .current
option.deliveryMode = .highQualityFormat
PHImageManager.default().requestAVAsset(forVideo: phAsset, options: option) { (avAsset, _, _) in
    if let avAsset = avAsset as? AVURLAsset {
        let fileURL = avAsset.url
        // upload by fileURL
    }
}

这套代码遇到的问题很可能是iOS 10之前的系统上传失败,之后的基本还是可以传成功的,主要是因为这个url路径在低版本系统访问受限。

正确的姿势应该是先把视频导出到沙盒然后从本地上传,那么如何copy到本地呢?答案是使用PHAssetResourceManager,这个类出现的比较晚在iOS 9才引入的,就是为了方便资源管理,可以通过他将本地相册的资源写入沙盒然后上传沙盒的资源。

let resources = PHAssetResource.assetResources(for: phAsset)
let options = PHAssetResourceRequestOptions()
options.isNetworkAccessAllowed = true
PHAssetResourceManager.default().writeData(for: assetResource, toFile: videoURL, options: options, completionHandler: { (error) in
    // upload by videoURL
    
})

但是这并非就万事大吉了,接下来的一个bug就是,通过这种方式如果上传用户已经编辑过的资源会发现它上传的是编辑之前的(比如说用户将60s的视频通过系统相册剪辑到50s,它上传的还是60s的),因为它相比较于PHImageManager请求可以设置PHVideoRequestOptions.version它缺少了这个信息,查找api也没有发现可以用的设置,所以这种方式还是不可取(如果有朋友知道怎么使用这种方式获取不同的version可以留言告诉我)。所以这时可以采用PHImageManager的另一个方法requestExportSession(xxx)将视频导出到沙盒然后上传,但是这么做的另一个小问题就是如果想要导出原始视频就不太可能了,只能尽可能拿到一个更高清晰度的视频。

let videoOption = PHVideoRequestOptions()
videoOption.version = PHVideoRequestOptionsVersion.current
videoOption.isNetworkAccessAllowed = true
PHImageManager.default().requestExportSession(forVideo: phAsset, options: videoOption, exportPreset: AVAssetExportPresetHighestQuality) { (exportSession, info) in
    if let exportSession = exportSession {
        exportSession.outputURL = videoURL
        exportSession.outputFileType = AVFileType.mp4
        exportSession.exportAsynchronously {
        if exportSession.status == AVAssetExportSession.Status.completed {
            // upload by videoURL
        }
    }
}
评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!