从 SwiftUI 视图中访问 actor 的隔离状态

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

我正在尝试了解一种设计模式,用于从 SwiftUI 视图中访问 actor 类型中保存的隔离状态。

使用这个天真的代码:

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)
            }
        }
    }
}

可以理解,当我尝试访问独立值时出现编译器错误 Actor-isolated property 'num' can not be referenced from the main actor。但是我不明白如何在视图中显示这些数据。我想知道我是否需要一个观察 actor 并在主线程上更新自身的 ViewModel,但出现编译时错误 Actor-isolated property '$num' can not be referenced from a non-isolated context.

class ViewModel: ObservableObject {
    
    let model: Model
    @Published var num: Int
    let cancellable: AnyCancellable
    
    init() {
        let model = Model()
        self.model = model
        self.num = 0
        self.cancellable = model.$num
            .receive(on: DispatchQueue.main)
            .sink { self.num = [=11=] }
    }
    
}

其次,想象一下如果这段代码确实编译了,那么当我点击界面没有在主线程上更新的按钮时我会得到另一个错误......我再次不确定如何从内部实现这一点演员?

您需要在您的视图模型(名为 Model)上使用 MainActor,表明其中的所有调度都在主线程上(当然假设您将使用新的 swift 并发它的系统)。

所以它看起来像

@MainActor 
class Model: ObservableObject {
    @Published var num: Int = 0

    func updateNumber(_ newNum: Int) {
        self.num = newNum
    }
}

注意:我建议在class内进行所有更新,因为某些地方的人可能会忘记以正确的方式更新它。