美文网首页
PHPickerViewController 选取照片报错处理

PHPickerViewController 选取照片报错处理

作者: zackzheng | 来源:发表于2024-01-11 11:57 被阅读0次

    PHPickerViewController,来自 iOS 14 推出的 PhotoKit 框架,可替代 UIImagePickerController。

    苹果在宣传中说它是基于系统的相册 App 的,具有与系统相册一致的 UI 和操作方式,可以保证用户体验的一致性。并且和相册 App 一样,支持通过人物、地点等关键信息来搜索照片。并且 PHPicker 是在独立进程中运行的,与宿主 App 无关,宿主 App 也无法通过截屏 api 来获取当前屏幕上的照片信息。为了保护用户隐私,苹果真的是在各种细节上严防死守。

    获取照片

    class ViewController: UIViewController {
        /// 选择照片
        func selectPhoto() {
    
            var configuration = PHPickerConfiguration()
            configuration.filter = .images // 只显示图片
            configuration.selectionLimit = 1 // 最多允许选择的数量,默认值为1
            configuration.preferredAssetRepresentationMode = .automatic // 自动根据设备和资源类型选择最佳预览模式
    
            let picker = PHPickerViewController(configuration: configuration)
            picker.modalPresentationStyle = .fullScreen
            picker.delegate = self
            present(picker, animated: true, completion: nil)
        }
    }
    
    // MARK: - PHPickerViewControllerDelegate
    extension ViewController: PHPickerViewControllerDelegate {
    
        func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
            
            self.presentedViewController?.dismiss(animated: true)
            result.itemProvider.loadObject(ofClass: UIImage.self) { [weak self] image, error in
                        
                guard let self = self else { return }
                guard let image = image as? UIImage else {
                    /// 错误处理
                    return
                }                    
                self.handle(uiImage: image)
            }
        }
    }
    

    选取手机拍的照片可以正常转换成 UIImage,但是选取网络下载的照片。
    报错如下:

    Could not coerce an item to class UIImage
    

    报错尝试

    loadObject 方法的第一个参数类型是 NSItemProviderReading 协议,文档没有提示什么类型遵循该协议。

    发现 NSItemProvider 有个 canLoadObject 方法,可以判断是否可以转换。和 loadObject 方法的参数类型一样,都是 NSItemProviderReading 类型。

    let a = result.itemProvider.canLoadObject(ofClass: AVURLAsset.self)
    let b = result.itemProvider.canLoadObject(ofClass: NSString.self)
    let c = result.itemProvider.canLoadObject(ofClass: NSURL.self)
    let d = result.itemProvider.canLoadObject(ofClass: NSUserActivity.self)
    let e = result.itemProvider.canLoadObject(ofClass: UIImage.self)
    

    发现网络下载的照片,这几种类型都无法转换。
    使用 Data 提示不符合 NSItemProviderReading,尝试 NSData 也不行。

    let f = result.itemProvider.canLoadObject(ofClass: NSData.self)
    

    报错如下:

    Instance method 'loadObject(ofClass:completionHandler:)' requires that 'NSData' conform to '_ObjectiveCBridgeable'
    

    发现 NSItemProvider 有另一个方法 loadFileRepresentation,completionHandler 回调的第一个参数是 URL,于是试了下,可以获取到图片的本地 URL。

    result.itemProvider.loadFileRepresentation(forTypeIdentifier: UTType.image.identifier,
                                               completionHandler: { [weak self] url, error  in
      do {
        if let url = url {
          let imageData = try Data(contentsOf: url)
          if let image = UIImage(data: imageData) {
            self?.handle(image: image)
          } else {
            /// 错误处理
          }
        } else {
          /// 错误处理
        }
      } catch let error {
        /// 错误处理
      }
    })
    

    最终处理

    // MARK: - PHPickerViewControllerDelegate
    extension ViewController: PHPickerViewControllerDelegate {
    
        func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
            
            self.presentedViewController?.dismiss(animated: true)
            
            guard let result = results.first else {
                return
            }
    
            if result.itemProvider.canLoadObject(ofClass: UIImage.self) {
                
                result.itemProvider.loadObject(ofClass: UIImage.self) { [weak self] image, error in
                    
                    guard let self = self else { return }
                    guard let image = image as? UIImage else {
                        /// 错误处理
                        return
                    }
                    
                    self.handle(image: image)
                }
            } else {
                result.itemProvider.loadFileRepresentation(forTypeIdentifier: UTType.image.identifier,
                                                           completionHandler: { [weak self] url, error  in
                    do {
                        if let url = url {
                            let imageData = try Data(contentsOf: url)
                            if let image = UIImage(data: imageData) {
                                self?.handle(image: image)
                            } else {
                                /// 错误处理
                            }
                        } else {
                            /// 错误处理
                        }
                    } catch let error {
                        /// 错误处理
                    }
                })
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:PHPickerViewController 选取照片报错处理

          本文链接:https://www.haomeiwen.com/subject/ntstodtx.html