Phi*_*den 7 concurrency swift swiftui
我试图理解一种设计模式,用于从 SwiftUI 视图中访问参与者类型中保存的隔离状态。
采取这个简单的代码:
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)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
Actor-isolated property 'num' can not be referenced from the main actor可以理解的是,当我尝试访问隔离值时,我收到了编译器错误。但我不明白如何在视图中显示这些数据。我想知道我是否需要一个 ViewModel 来观察 actor,并在主线程上更新自身,但会出现编译时错误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 = $0 }
}
}
Run Code Online (Sandbox Code Playgroud)
其次,想象一下,如果这段代码确实编译了,那么当单击按钮时,我会收到另一个错误,表明界面没有在主线程上更新......我再次不确定如何从演员内部实现这一点?
您需要MainActor在视图模型(名为Model)上使用,指示其中的所有分派都在主线程上(当然假设您将为其使用新的 swift 并发系统)。
所以它看起来像
@MainActor
class Model: ObservableObject {
@Published var num: Int = 0
func updateNumber(_ newNum: Int) {
self.num = newNum
}
}
Run Code Online (Sandbox Code Playgroud)
注意:我建议在课堂上进行所有更新,因为某个地方的某人可能会忘记以正确的方式更新它。
接受的答案可能不适合所有用例。
就我而言,我希望ObservableObject保留actor,但从 SwiftUI 视图访问其属性之一。所以我@MainActor只添加了该属性。
这意味着属性也只需要从主线程更新,如下所示。
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
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3786 次 |
| 最近记录: |