iOS Swift框架中VNDocumentCameraViewController点击保存无法关闭求助
问题分析与修复方案
我帮你梳理下核心问题所在,以及对应的修复步骤:
问题根源拆解
- 错误的控制器展示方式:你用
addChild+addSubview的方式把VNDocumentCameraViewController加到clientView中,但这个扫描控制器是Apple设计用来模态弹出的组件,这种子视图嵌入的方式会破坏它内部的导航逻辑和生命周期,导致后续调用controller.dismiss(animated: true)完全无效——因为dismiss仅对通过present方法弹出的控制器生效。 - 无意义的提前dismiss:在
createTaskController里,你刚添加完子控制器就立刻调用scannerViewController.dismiss(animated: true),这不仅逻辑矛盾,而且本身就是无效调用。 - 临时实例被提前释放:示例代码里
A8Scan(self).showScanner()创建的是临时实例,方法执行结束后这个实例会被ARC自动释放,导致扫描控制器的代理方法(比如扫描完成/取消的回调)根本无法触发。
修复后的框架代码
改用系统标准的模态present方式展示扫描控制器,同时修正实例生命周期问题:
public class A8Scan: NSObject, VNDocumentCameraViewControllerDelegate { weak var parentVC: UIViewController? var imageNew: UIImage? // 初始化时绑定父控制器,避免临时实例被释放 public init(_ parentVC: UIViewController) { self.parentVC = parentVC super.init() } public func showScanner(){ createTaskController() print("Called Build") } private func createTaskController(){ guard let parentVC = parentVC else { return } let scannerViewController = VNDocumentCameraViewController() scannerViewController.delegate = self // 改用官方推荐的模态present方式 parentVC.present(scannerViewController, animated: true) } public func imageFromFile(result: @escaping (_ image: UIImage?) -> Void){ result(imageNew) } public func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFinishWith scan: VNDocumentCameraScan) { guard scan.pageCount >= 1 else { controller.dismiss(animated: true) return } let originalImage = scan.imageOfPage(at: 0) let newImage = compressedImage(originalImage) imageNew = newImage print("new image size::\(newImage.size)") // 此时dismiss会正常生效,因为控制器是通过present弹出的 controller.dismiss(animated: true) } public func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFailWithError error: Error) { print("Scan error: \(error.localizedDescription)") controller.dismiss(animated: true) } public func documentCameraViewControllerDidCancel(_ controller: VNDocumentCameraViewController) { controller.dismiss(animated: true) } func compressedImage(_ originalImage: UIImage) -> UIImage { // 把压缩质量调低一点,1.0等于无压缩,0.5-0.8是更合理的平衡值 guard let imageData = originalImage.jpegData(compressionQuality: 0.7), let reloadedImage = UIImage(data: imageData) else { return originalImage } return reloadedImage } }
修复后的示例项目调用代码
将扫描工具实例作为ViewController的属性持有,避免被提前释放:
class ViewController: UIViewController { // 持有扫描工具实例,保证代理方法能正常触发 var scanTool: A8Scan? @IBAction func btnAction(_ sender: Any) { scanTool = A8Scan(self) scanTool?.showScanner() // 如果需要在扫描完成后获取图片,可以在这里添加回调逻辑 // 比如: // DispatchQueue.main.asyncAfter(deadline: .now()+2) { // self.scanTool?.imageFromFile { image in // print("Got scanned image: \(image)") // } // } } }
额外说明
VNDocumentCameraViewController内部包含完整的导航交互逻辑,模态present是Apple官方指定的展示方式,用子视图嵌入会破坏这些原生逻辑,导致dismiss、按钮交互等功能失效。- 压缩图片时,
compressionQuality:1不会对图片体积有任何优化,建议根据需求调整到0.5-0.8之间,平衡图片质量和体积。
内容的提问来源于stack exchange,提问作者PvUIDev
相关产品推荐
相关产品推荐

