`defer` in async Task & actor isolation

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

The following seems to work:

defer { Task { @MainActor in self.progress = nil } }