所以我有这个代码:
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 个错误:
shared
:静态属性“共享”不是并发安全的,因为非“可发送”类型“DocumentScanDelegate”可能具有共享可变状态;这是 Swift 6 语言模式下的错误
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”属性无效
在评论中跟进我们的对话这里。
考虑到你的最后一个问题,我不太确定为什么这会起作用,但我尝试将严格的并发检查设置为“完成”,并且它没有抱怨。我最好的猜测是,在任务闭包中捕获
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)
}
}
}