在本篇文章中,我将详细介绍如何正确使用PHPicker以及何时应该使用PHPicker。我撰写这篇文章的原因是:在尝试使用PHPicker访问资源库时遇到了一些问题。互联网上的许多文章提供的方法都是错误的,从而导致了对PHPicker和iOS权限的一些核心问题的误解。
01
PHPicker是什么?
PHPickerViewController
PHPickerConfiguration
PHPickerFilter
PHPickerResult
letphotoLibrary=()varconfig=PHPickerConfiguration(photoLibrary:photoLibrary)letselectedCount==min(4-selectedCount,4)=(type==.pic?limited:1)=(type==.pic?.images:.videos)letpickerViewController=PHPickerViewController(configuration:config)=?.present(pickerViewController,ani
02
真的需要用户授权吗?
当用户给予受限访问模式时,如果需要获得未授权的额外资源,网络上很多文章建议你使用PHAsset和PHPicker来获取额外的数据,这样做的问题是,你必须具有访问资源库的权限,这违背了苹果建议的使用PHPicker的初衷:在不请求权限的情况下使用的选择器。
我们来模拟一下流程:你的的应用程序请求访问用户资源库的权限,用户说:“我将只给这个应用程序有限的访问一些照片。”此时,如果你的应用程序打开PHPicker并显示所有的照片;用户说:“奇怪,我以为我只给有限的访问权限,为什么所有照片都有?”;接下来,用户选择了一张他没有给我们访问权限的照片。应用程序现在需要什么都不做,为了使用PHAsset获得他选择的照片的元数据(metadata),他们必须再次更新他们的权限。用户感到困惑。
所以,如果你的目的非常明确,就是需要用户给予额外的资源授权来获得PHAsset对象,应该使用iOS14的新().presentLimitedLibraryPicker(from:vc),反之,使用PHPicker不应该申请获得用户授权,正确的做法是使用PHPickerViewControllerDelegate返回的NSItemProvider获得元数据(metadata)信息,我将在稍后详细介绍。
03
使用PHPicker的方式
1、错误方式
下面这段代码是网络上广泛被转载的一段错误代码:
importUIKitimportPhotosUIclassPhotoKitPickerViewController:UIViewController,PHPickerViewControllerDelegate{@IBActionfuncpresentPicker(_ser:Any){letphotoLibrary=()letconfiguration=PHPickerConfiguration(photoLibrary:photoLibrary)letpicker=PHPickerViewController(configuration:configuration)=selfpresent(picker,animated:true)}funcpicker(_picker:PHPickerViewController,didFinishPickingresults:[PHPickerResult]){(animated:true)letidentifiers=(\.assetIdentifier)letfetchResult=(withLocalIdentifiers:identifiers,options:nil)//TODO:DosomethingwiththefetchresultifyouhavePhotosLibraryaccess}}在这段代码中,你使用PHPickerViewController选择了受限制的资源,但是在调用时返回了一个空结果。这是因为fetchAssets方法只能检索用户授权访问的所有资源,而在受限制模式下,只有最近的受限制资源可供访问,所以这种方式是错误的!
2、正确方式
04
通过前一步骤,我们已经知道了资源的类型。接下来通过NSItemProvider的API加载图片内容和获得元数据信息;查阅NSItemProvider(1)文档,可以看到加载数据,主要提供了下面几种API:
loadDataRepresentation:返回资源Data数据
loadFileRepresentation:返回资源URL
loadObject:指定资源类型返回
这里我推荐使用loadDataRepresentation,返回Data数据,方便下一步获得元数据信息。
在处理业务model转换函数中,由于Data类型很容易转换成UIImage,并且通过将Data转换为CFData类型,可以通过系统预设的key/value键值对获得元数据信息,
letimgSrc=CGImageSourceCreateWithData(data,optionsasCFDictionary)letmetadata=CGImageSourceCopyPropertiesAtIndex(imgSrc,0,optionsasCFDictionary)colorModel=metadata[kCGImagePropertyColorModel]as?StringpixelWidth=metadata[kCGImagePropertyPixelWidth]as?Double;pixelHeight=metadata[kCGImagePropertyPixelHeight]as?Double;
这里我们使用了Github上开源的ExifData(2)代码,完整实现了所有字段的获取封装,使用起来非常方便。
funccreatePhotoResourcesModel(data:Data?,assetIdentifier:String?)-SNSResourcesModel?{guardletimageData=data,letuiimage=UIImage(data:imageData)else{returnnil}letmodel=SNSResourcesModel()==.=.==uiimageletexifData=ExifData(data:imageData)=Int(??0)=Int(??0)==.GIF{==imageData}returnmodel}05
处理特殊格式图片
如果用户在资源库中选择了一张WebP格式图片或者GIF动图,由于展示所需代码和形式均不同,所以需要特别区分,那么如何来区别处理呢?
我们可以通过UTType来具体区分不同类型,UTType是UniformTypeIdentifier的缩写,用于标识特定类型的文件或数据。在macOS和iOS等操作系统中,UTType通常用于识别文件类型、将文件分组到合适的应用程序中、在不同应用程序之间共享数据等。
UTType由两部分组成:类型标识符(typeidentifier)和类型标签(typetag)。类型标识符是一串唯一的字符串,用于标识特定类型的文件或数据,通常采用反向DNS风格的命名方式,如、等。类型标签是一个可选的字符串,用于描述特定类型的文件或数据,例如"PDFdocument"或"JPEGimage"等。
if(()){//图片处理//判断(){//处理webp}//判断(){//处理GIF}}06
06
获取加载进度
当获取的资源文件较大时,我们需要获得加载数据的进度,此时可以使用NSItemProvider的加载数据函数提供的返回值NSProgress对象。
varprogress:Progress?progress=(forTypeIdentifier:){data,errorin//}//添加观察者progress?.addObserver(self,forKeyPath:"fractionCompleted",options:[.new],context:nil)overridefuncobserveValue(forKeyPathkeyPath:String?,ofobject:Any?,change:[NSKeyValueChangeKey:Any]?,context:UnsafeMutableRawPointer?){ifkeyPath=="fractionCompleted"{print("fractionCompleted=\(?.fractionCompleted)")}}在上面的示例代码中,我们首先创建了一个NSItemProvider对象和一个指定类型标识符。然后,我们使用loadDataRepresentation(forTypeIdentifier:completionHandler:)方法加载数据,并返回一个NSProgress对象。我们可以将该对象添加为观察者,并在观察者的回调方法中更新进度条的值。
请注意,NSProgress对象是线程安全的,因此可以在不同的线程中使用。此外,如果你需要在多个地方使用同一个NSProgress对象;
NSProgress对象的fractionCompleted属性,该属性表示任务的完成度,其值在0.0和1.0之间。
06
总结
本文要点包含以下:
PHPicker是iOS14开始引入的新组件,它允许在不需要用户授权的情况下访问照片库的所有资源;
使用PHPicker的正确方式是通过PHPickerViewControllerDelegate回调返回的NSItemProvider来获取所选资源,而不是通过PHAsset来获取,后者需要提前获取用户的相册访问授权;
通过UTType可以进一步判断特殊格式资源如webp、gif等进行不同处理;
可以通过NSProgress监听资源加载进度;
正确使用PHPicker可以避免引起用户疑惑,提高用户体验,是iOS14访问多媒体资源的推荐方式。
总之,本文详细介绍了在iOS14中如何正确使用PHPicker访问用户选择的部分照片资源,其要点是不需要提前获取授权,通过NSItemProvider处理多媒体资源,这是一种更符合系统设计初衷和提高用户体验的方式。
标注参考链接:(1)
(2)
其他参考链接:(1)
(2)
(3)
(4)
(5)
作者:狐友靳凯
出处: