I am restructuring my project and I repeatedly bump into the following problem:
In my View structs I have functions that are executed from e.g. Buttons. Some of these functions need to use system functions that require a delegate. So far I had these functions collected in a model that conformed to the delegate protocol. This is now not anymore possible since Views are value types and do not allow to conform to these protocols.
The following example demonstrates the problem:
extension MyView {
public func downloadSomething() async {
let (localeUrl, _) = try await URLSession.shared.download(
from: URL(string: "myURL")!, delegate: downloadHelper)
}
}
My approach was to create a separate class that conforms to the required protocol, like this:
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)")
}
}
}
This works in Swift5, but Swift6 complains about the stored property in my implicit Sendable DownloadHelper class. So I cant migrate this to Swift6 !
How can this be solved ? Is there a better design pattern ?
DownloadHelper
is not sendable because progressObservation
can be modified concurrently. You just need to add a synchronisation mechanism. For example, you can use a 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)")
}
}
}
If you need to support older OS versions, you could use NSLock
or similar. In this case, the compiler cannot check that you have done the synchronisation correctly, so you need to add @unchecked Sendable
:
final class DownloadHelper: NSObject, URLSessionTaskDelegate, @unchecked Sendable {
// do your synchronisation here...
}