lhunath
(Maarten Billemont)
1
Under Swift, the typical paradigm of try-catch-finally has been replaced with do-defer-catch, where defer plays the role of finally, ensuring code is executed regardless of the error handling path.
It seems that in an asynchronous environment within Swift Concurrency, this paradigm may break down:
struct SandView: View {
@State private var progress: Progress?
var body: some View {
Button("Sand Box") {
Task {
do {
self.progress = .init()
defer { self.progress = nil } // property 'progress' isolated to global actor 'MainActor' can not be mutated from a non-isolated context
try await withCheckedThrowingContinuation { $0.resume() }
} catch {
print("uh oh: \(error)")
}
}
}
}
}
Is there a solution to this or an alternative paradigm that can be recommended?
1 Like
rhx
2
The following seems to work:
defer { Task { @MainActor in self.progress = nil } }
1 Like
mickeyl
(Dr. Mickey Lauer)
3
FWIW, Async, Rethrows, and Defer - #9 by Joe_Groff is proposing an async defer, I hope it'll get into a pitch eventually.
2 Likes
Joe_Groff
(Joe Groff)
4
TBC, I am not personally actively working on a proposal for this, so if community folks are interested in proposing it, don't let me stop you.
Note that there was a bug where defer was incorrectly being considered to have a different isolation from the surrounding function. That bug should be fixed, but let us know if you're still seeing it.
7 Likes