如何将 `VNDocumentCameraViewControllerDelegate` 转换为 Swift 6 并发

问题描述 投票:0回答:1

所以我有这个代码:

fileprivate class DocumentScanDelegate: NSObject, VNDocumentCameraViewControllerDelegate {
  
  static let shared = DocumentScanDelegate()

  var compressionQuality: CGFloat = 1
  var onScanSuccess: (UIImage) -> Void = { _ in }
  
  func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFinishWith scan: VNDocumentCameraScan) {
    
    controller.dismiss(animated: true)
    
    guard scan.pageCount >= 1 else { return }
    let lastPage = scan.imageOfPage(at: scan.pageCount - 1)
    let compressed = lastPage.compressed(quality: compressionQuality)
    onScanSuccess(compressed)
  }
  
  func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFailWithError error: Error) {
    controller.dismiss(animated: true)
  }
  
  func documentCameraViewControllerDidCancel(_ controller: VNDocumentCameraViewController) {
    controller.dismiss(animated: true)
  }
  

}

我有 2 个错误:

  1. shared

静态属性“共享”不是并发安全的,因为非“可发送”类型“DocumentScanDelegate”可能具有共享可变状态;这是 Swift 6 语言模式下的错误

  1. 3 个
    controller.dismiss
    电话:

在同步非隔离上下文中调用主参与者隔离实例方法“dismiss(animated:completion:)”;这是 Swift 6 语言模式下的错误

两者都有道理。所以我所做的就是将

@MainActor
添加到
DocumentScanDelegate 
。然后第一个警告消失了。但第二个警告变成:

主参与者隔离实例方法“documentCameraViewController(_:didFinishWith:)”不能用于满足非隔离协议要求;这是 Swift 6 语言模式下的错误

然后我用

@preconcurrency
来注释
VNDocumentCameraViewControllerDelegate
一致性:

@MainActor
fileprivate class DocumentScanDelegate: NSObject, @preconcurrency VNDocumentCameraViewControllerDelegate {
  ...
}

这个

@preconcurrency
技巧与WWDC 2024的视频非常相似(https://developer.apple.com/videos/play/wwdc2024/10169/?time=1520

错误变为:

主参与者隔离实例方法“documentCameraViewController(_:didFinishWith:)”不能用于满足非隔离协议要求;这是 Swift 6 语言模式下的错误

出现以下子错误:

“VNDocumentCameraScan”类不符合“可发送”协议

然后我使用

@preconcurrency
导入:

@preconcurrency import VisionKit

同样的警告仍然存在。

还有一个新警告(为什么?):

模块“VisionKit”上的“@preconcurrency”属性无效

ios swift concurrency
1个回答
0
投票

在评论中跟进我们的对话这里

考虑到你的最后一个问题,我不太确定为什么这会起作用,但我尝试将严格的并发检查设置为“完成”,并且它没有抱怨。我最好的猜测是,在任务闭包中捕获

controller
不是问题,因为保证只能在那里的
@MainActor
上访问它。

import VisionKit

private class DocumentScanDelegate: NSObject, VNDocumentCameraViewControllerDelegate {
    @MainActor
    static let shared = DocumentScanDelegate()

    var compressionQuality: CGFloat = 1
    var onScanSuccess: (UIImage) -> Void = { _ in }

    func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFinishWith scan: VNDocumentCameraScan) {
        Task { @MainActor in 
            controller.dismiss(animated: true)
        }
        
        guard scan.pageCount >= 1 else { return }
        let lastPage = scan.imageOfPage(at: scan.pageCount - 1)
        let compressed = lastPage.compressed(quality: compressionQuality)
        onScanSuccess(compressed)
    }

    func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFailWithError error: Error) {
        Task { @MainActor in
            controller.dismiss(animated: true)
        }
    }

    func documentCameraViewControllerDidCancel(_ controller: VNDocumentCameraViewController) {
        Task { @MainActor in
            controller.dismiss(animated: true)
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.