如何在View成员函数中使用委托?

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

我正在重组我的项目,我反复遇到以下问题:

在我的视图类中,我有从例如执行的函数按钮。其中一些函数需要使用需要委托的系统函数。到目前为止,我已将这些函数收集在符合委托协议的模型中。现在这不再可能了,因为视图是值类型并且不允许遵守这些协议。

以下示例演示了该问题:

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!

如何解决这个问题?有没有更好的设计模式?

swift swiftui design-patterns concurrency swift6
1个回答
0
投票

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...
}
© www.soinside.com 2019 - 2024. All rights reserved.