为@Published变量添加@MainActor是否会改变父类的Actor归属?
关于@MainActor与@Published结合的行为疑问
先看这段可以正常运行的代码:
import SwiftUI class VM:ObservableObject{ @Published var keepStuff = 0 init(){ keepStuff = 1 } } struct MyView:View{ @ObservedObject var vm = VM() var body: some View{ Text("Hello World") Text(String(vm.keepStuff)) } }
但如果给keepStuff属性同时加上@MainActor修饰,就会收到报错提示:
note: mutation of this property is only permitted within the actor
修改后的代码如下:
class VM:ObservableObject{ @MainActor @Published var keepStuff = 0 init(){ keepStuff = 1 } }
不过如果给整个类或者init方法单独添加@MainActor,报错就会消失。
我之前的认知是@Published变量默认属于MainActor,因此在非MainActor中更新时会报错。但此处为@Published变量添加@MainActor后,似乎类的其余部分不再属于MainActor。有人能解释该行为吗?
解释
- @Published本身不绑定MainActor:
@Published的核心作用是把属性变化发布给订阅者,SwiftUI在接收这些变化后会自动切换到MainActor更新UI,但属性本身的读写权限默认和它所在的上下文一致,并没有被强制限定在MainActor。 - 单个属性加@MainActor的影响:当你只给
keepStuff加上@MainActor,相当于把这个属性的读写操作限定在了MainActor上下文里,但类的其他部分(比如init方法)还是运行在默认的非Actor上下文。这时候在init里直接修改keepStuff,就属于从非MainActor环境访问MainActor专属的属性,自然触发权限报错。 - 给类/init加@MainActor的作用:如果给整个类标注
@MainActor,类的所有成员(包括init、所有属性)都会默认在MainActor上下文运行,修改keepStuff就符合权限要求;如果只给init加@MainActor,会让init的代码逻辑运行在MainActor里,修改该属性也就合法了。 - 澄清之前的误解:你之前觉得
@Published默认属于MainActor,可能是混淆了SwiftUI的UI更新机制——@Published的变化通知会被SwiftUI处理到MainActor,但属性本身的读写权限并没有被强制约束,必须主动用@MainActor标注才会生效。
内容的提问来源于stack exchange,提问作者DrGonzoX
相关产品推荐
相关产品推荐

