You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中多层@ObservableObject嵌套时视图如何响应深层数据变化

Swift跨多层对象的数据源变更视图响应方案

问题根因

你提供的加入Middle层后代码失效的核心原因:
@ObservedObject是SwiftUI专用属性包装器,仅可在View结构体中使用,放在普通ObservableObject类的属性上不会产生任何观察效果。底层Test实例的@Published属性变更只会触发Test自身的objectWillChange事件,不会向上通知外层的Middle实例,因此监听Middle的视图无法收到更新通知。

系统性解决方案

方案1:手动转发嵌套ObservableObject变更(兼容iOS13+)

如果需要兼容旧系统版本,可以在中间层手动监听底层ObservableObject的变更事件,收到变更后转发当前层的变更通知即可:

import Combine

class Middle: ObservableObject {
    // 这里不需要加@ObservedObject,无效
    var test: Test = Test()
    private var cancellables = Set<AnyCancellable>()
    
    init() {
        // 监听底层Test的变更事件
        test.objectWillChange
            .sink { [weak self] _ in
                // 转发当前Middle层的变更通知
                self?.objectWillChange.send()
            }
            .store(in: &cancellables)
    }
}

如果有多层嵌套,每一层都按这个逻辑转发即可,无需修改其他业务代码。

方案2:使用Swift 5.9新增的@Observable宏(iOS17+/macOS14+)

新版Swift的观察体系完全解决了嵌套观察的问题,不需要额外写转发逻辑,也不需要使用@Published、@ObservedObject等修饰符,只要视图访问到的属性发生变更,就会自动触发刷新:

// 底层模型用@Observable修饰
@Observable class Test {
    var array: [String] = []
    var num: Int = 0
    
    func add() {
        array.append(String(num))
        num += 1
    }
}

// 中间层也用@Observable修饰
@Observable class Middle {
    var test: Test = Test()
}

struct testView: View {
    // 不需要@ObservedObject修饰
    var m = Middle()
    var body: some View {
        VStack {
            Button(action: { m.test.add() }) {
                Text("Add Item to Array")
            }
            Text("")
            Text("Items")
            // 只要这里访问了m.test.array,就会自动建立观察关系
            Text(Array(m.test.array).description)
        }
    }
}

方案3:依赖注入下沉,避免跨层传递

如果中间层不需要持有数据模型,可直接将底层数据通过EnvironmentObject注入到视图层,绕开中间层传递:

@main
struct app: App {
    // 全局持有底层数据实例
    var test = Test()
    var body: some Scene {
        WindowGroup {
            testView()
                // 注入到环境中
                .environmentObject(test)
        }
    }
}

struct testView: View {
    // 直接从环境中读取Test实例
    @EnvironmentObject var test: Test
    var body: some View {
        VStack {
            Button(action: { test.add() }) {
                Text("Add Item to Array")
            }
            Text("")
            Text("Items")
            Text(Array(test.array).description)
        }
    }
}

注意事项

  • @ObservedObject仅可用于SwiftUI的View结构体中,不要在普通类属性上添加
  • 低版本兼容优先用手动转发方案,新系统优先使用@Observable宏减少冗余代码
  • 尽可能避免过深的嵌套观察,合理使用环境注入可以简化代码逻辑

内容的提问来源于stack exchange,提问作者John Sorensen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 18:15:02