SwiftUI中嵌套ObservableObject如何引用父级EnvironmentObject
错误原因
@EnvironmentObject是SwiftUI专为View层设计的属性包装器,只能在符合View协议的类型中使用,不能在ObservableObject类型的自定义模型类里声明,所以你在SubModel里加的这个属性完全无效,运行时找不到对应的Model实例就会触发崩溃。
解决方案1:手动注入父模型引用(推荐,改动最小)
直接在SubModel里持有父Model的弱引用(避免循环引用),父Model初始化时把自身传给SubModel即可,修改后代码如下:
class SubModel: ObservableObject { // 加weak避免循环引用:父Model强持有subModel,subModel不能再强持有父Model weak var model: Model? func run() { model?.email = "new@test.com" } } class Model: ObservableObject { @Published var subModel: SubModel @Published var email: String = "" init() { let sub = SubModel() // 初始化时把自身注入到子模型里 sub.model = self self.subModel = sub } }
这个方案符合常规的模型层依赖注入逻辑,不需要改上层View的代码即可直接运行。
解决方案2:拆分逻辑到父层处理
如果不想让子模型持有父引用,可以把跨模型的操作抽离到父Model或者View层实现:
class Model: ObservableObject { @Published var subModel = SubModel() @Published var email: String = "" // 父层提供修改方法,不需要子模型持有自身引用 func updateEmail(_ newEmail: String) { email = newEmail } } // View层调用示例 struct MainView: View { @EnvironmentObject var model: Model var body: some View { Button(action: { // 直接调用父层方法修改 model.updateEmail("new@test.com") }) { Text("Click me") } } }
额外提示:嵌套ObservableObject的场景下,子模型的属性变更不会自动触发父模型的objectWillChange事件,要么手动在子模型变更时调用父模型的
objectWillChange.send(),要么把SubModel改成结构体,即可通过@Published自动监听属性变更。
内容的提问来源于stack exchange,提问作者joshuakcockrell
相关产品推荐
相关产品推荐

