swiftconcurrencyswiftui

Accessing an actor's isolated state from within a SwiftUI view


I'm trying to understand a design pattern for accessing the isolated state held in an actor type from within a SwiftUI view.

Take this naive code:

actor Model: ObservableObject {
    @Published var num: Int = 0
    
    func updateNumber(_ newNum: Int) {
        self.num = newNum
    }
}

struct ContentView: View {
    @StateObject var model = Model()
    
    var body: some View {
        Text("\(model.num)") // <-- Compiler error: Actor-isolated property 'num' can not be referenced from the main actor
        Button("Update number") {
            Task.detached() {
                await model.updateNumber(1)
            }
        }
    }
}

Understandably I get the compiler error Actor-isolated property 'num' can not be referenced from the main actor when I try and access the isolated value. Yet I can't understand how to display this data in a view.


Solution

  • The accepted answer might not suite all use cases.

    In my case, I want the ObservableObject to remain an actor, but access one of its property from a SwiftUI view. So I added @MainActor only to that property.

    This means that property also needs to be updated only from the main thread as shown below.

    actor Model: ObservableObject {
      @MainActor @Published var num: Int = 0
    
      func updateNumber(_ newNum: Int) {
        Task { @MainActor in 
          self.num = newNum
        }
      }
    
      // all other properties and functions will remain isolated to the actor
    }