iOS Swift:VisionKit文档扫描框架如何将图片传递至示例项目?
解决VisionKit扫描框架无法向示例项目传递图片的问题
我来帮你搞定这个问题!你的核心问题是completion handler的触发时机完全错误——在imageFromFile方法里,你刚弹出扫描控制器就立刻检查imageNew,这时候用户还没开始扫描,imageNew必然是nil,导致completion直接返回了空值,根本没等到扫描完成后的结果。
问题代码分析
- 你的
imageFromFile方法中,present相机控制器后马上执行if imageNew != nil判断,这时候扫描流程还没启动,所以直接调用result(nil)结束了completion。 - 每次调用
A8Scan(self).imageFromFile都会创建新的A8Scan实例,扫描完成后原实例已被释放,completion自然无法触发。 - 没有在扫描完成、失败或取消的回调中正确触发completion,导致结果无法传递到示例项目。
修改后的框架代码(A8Scan类)
public class A8Scan: NSObject, VNDocumentCameraViewControllerDelegate { var imageNew: UIImage? var statusImage: UIImageView? private var clientView: UIViewController? // 新增:用于保存外部传入的completion handler private var imageCompletion: ((UIImage?) -> Void)? public init(_ viewController:UIViewController){ self.clientView = viewController } public func showScanner(imgData: UIImage?){ self.createTaskController(img: imgData) print("Called Build") } private func createTaskController(img: UIImage?){ let scannerViewController = VNDocumentCameraViewController() scannerViewController.delegate = self self.clientView?.present(scannerViewController,animated:true,completion: { self.imageNew = img }) } // 重写后的imageFromFile方法:只保存completion并弹出扫描器 public func imageFromFile(completion: @escaping (_ image: UIImage?) -> Void){ self.imageCompletion = completion let scannerViewController = VNDocumentCameraViewController() scannerViewController.delegate = self self.clientView?.present(scannerViewController,animated:true,completion: nil) } func set(image: UIImage) { self.statusImage?.image = image } public func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFinishWith scan: VNDocumentCameraScan) { guard scan.pageCount >= 1 else { controller.dismiss(animated: true) { // 无扫描页面时返回nil self.imageCompletion?(nil) self.imageCompletion = nil } return } let originalImage = scan.imageOfPage(at: 0) let newImage = compressedImage(originalImage) imageNew = newImage set(image: imageNew!) print("new image::\(newImage.size)") // 相机关闭后再触发completion传递图片 controller.dismiss(animated: true) { self.imageCompletion?(newImage) // 清空completion避免内存泄漏 self.imageCompletion = nil } } public func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFailWithError error: Error) { print(error) controller.dismiss(animated: true) { self.imageCompletion?(nil) self.imageCompletion = nil } } public func documentCameraViewControllerDidCancel(_ controller: VNDocumentCameraViewController) { controller.dismiss(animated: true) { // 用户取消扫描时返回nil self.imageCompletion?(nil) self.imageCompletion = nil } } func compressedImage(_ originalImage: UIImage) -> UIImage { guard let imageData = originalImage.jpegData(compressionQuality: 1), let reloadedImage = UIImage(data: imageData) else { return originalImage } return reloadedImage } }
修改后的示例项目调用代码
// 在你的ViewController类中添加属性,复用同一个A8Scan实例 private let scanner = A8Scan(self) @IBAction func btnAction(_ sender: Any) { scanner.imageFromFile { [weak self] image in guard let self = self else { return } if let scannedImage = image { print("成功获取扫描图片:\(scannedImage.size)") // 这里可以将图片赋值给你的UIImageView或进行其他处理 } else { print("扫描失败或用户取消操作") } } }
关键修改点说明
- 保存completion handler:新增
imageCompletion属性,把外部传入的completion暂存起来,等待扫描流程结束后再触发。 - 延迟触发completion:在扫描完成、失败、取消的回调中,等到相机控制器关闭后再调用completion,确保结果能正确传递。
- 复用A8Scan实例:将
A8Scan作为ViewController的属性,避免每次调用都新建实例导致扫描完成后原对象被销毁。 - 内存安全:使用
[weak self]避免循环引用,调用完completion后清空imageCompletion防止内存泄漏。
内容的提问来源于stack exchange,提问作者PvUIDev
相关产品推荐
相关产品推荐

