我正在重组我的项目,我反复遇到以下问题:
在我的视图类中,我有从例如执行的函数按钮。其中一些函数需要使用需要委托的系统函数。到目前为止,我已将这些函数收集在符合委托协议的模型中。现在这不再可能了,因为视图是值类型并且不允许遵守这些协议。
以下示例演示了该问题:
extension MyView {
public func downloadSomething() async {
let (localeUrl, _) = try await URLSession.shared.download(
from: URL(string: "myURL")!, delegate: downloadHelper)
}
}
我的方法是创建一个符合所需协议的单独的类,如下所示:
final class downloadHelper: NSObject, URLSessionTaskDelegate {
var progressObservation: NSKeyValueObservation!
public func urlSession(_ session: URLSession, didCreateTask task: URLSessionTask) {
progressObservation = task.progress.observe(\.fractionCompleted) { progress, value in
print("Taskprogress \(progress)")
}
}
}
这在 Swift5 中有效,但 Swift6 抱怨我的隐式 Sendable downloadHelper 类中存储的属性。所以我无法将其迁移到 Swift6!
如何解决这个问题?有没有更好的设计模式?
DownloadHelper
不可发送,因为 progressObservation
可以同时修改。你只需要添加一个同步机制即可。例如,您可以使用 Mutex
。
let progressObservation = Mutex<NSKeyValueObservation?>(nil)
public func urlSession(_ session: URLSession, didCreateTask task: URLSessionTask) {
progressObservation.withLock {
$0 = task.progress.observe(\.fractionCompleted) { progress, value in
print("Taskprogress \(progress)")
}
}
}
如果您需要支持较旧的操作系统版本,您可以使用
NSLock
或类似的。在这种情况下,编译器无法检查你是否正确完成了同步,因此你需要添加 @unchecked Sendable
:
final class DownloadHelper: NSObject, URLSessionTaskDelegate, @unchecked Sendable {
// do your synchronisation here...
}