You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS Swift框架中VNDocumentCameraViewController点击保存无法关闭求助

问题分析与修复方案

我帮你梳理下核心问题所在,以及对应的修复步骤:

问题根源拆解

  1. 错误的控制器展示方式:你用addChild+addSubview的方式把VNDocumentCameraViewController加到clientView中,但这个扫描控制器是Apple设计用来模态弹出的组件,这种子视图嵌入的方式会破坏它内部的导航逻辑和生命周期,导致后续调用controller.dismiss(animated: true)完全无效——因为dismiss仅对通过present方法弹出的控制器生效。
  2. 无意义的提前dismiss:在createTaskController里,你刚添加完子控制器就立刻调用scannerViewController.dismiss(animated: true),这不仅逻辑矛盾,而且本身就是无效调用。
  3. 临时实例被提前释放:示例代码里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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:00:15