ObservableObject @Published @ObservedObject那些事

先理解这三个为什么要一起讲

它们是一套组合拳,缺一不可:

角色 是什么
ObservableObject 一个协议,贴在 class 上,宣告"我是可被观察的数据源"
@Published 一个 Property Wrapper,贴在属性上,宣告"这个属性变化时要通知订阅者"
@ObservedObject 一个 Property Wrapper,贴在 View 的属性上,宣告"我订阅这个数据源,它变化我就刷新"

为什么需要这套东西?@State 不够用吗?

@State 适合简单的值类型,但现实中你的数据模型往往是一个 class ,有很多属性和方法,且需要被多个平级 View 共享

swift 复制代码
// 一个用户信息模型,多个页面都要用
class UserModel {
   var name: String = "Tom"
   var age: Int = 18
   var score: Int = 0
   // ... 还有很多方法
}

把这个 class 塞进 @State 是行不通的------@State 是为值类型设计的,对 class 的引用地址变化不敏感,属性改了 UI 也不会刷新。


三件套的用法

swift 复制代码
// 第一步:让你的 class 遵守 ObservableObject 协议
class UserModel: ObservableObject {
   // 第二步:在需要触发 UI 刷新的属性上加 @Published
   @Published var name: String = "Tom"
   @Published var score: Int = 0
   var internalCache: String = ""  // 不加 @Published,改它不会刷新 UI
}

// 第三步:在 View 里用 @ObservedObject 订阅这个模型
struct ProfileView: View {
   @ObservedObject var user: UserModel

   var body: some View {
       VStack {
           Text(user.name)
           Text("\(user.score)")
           Button("加分") {
               user.score += 1   // 改 @Published 属性 → 触发 UI 刷新
           }
       }
   }
}

// 使用:顶层 View 用 @StateObject 持有并创建模型
struct ContentView: View {
   @StateObject var user = UserModel()

   var body: some View {
       ProfileView(user: user)
   }
}

三件套的本质

@Published 本质上是:

swift 复制代码
@propertyWrapper
public struct Published<Value> {
   // 每次 wrappedValue 被 set,就通过 objectWillChange 发出通知
   public var wrappedValue: Value
   // $score 拿到的是一个 Combine Publisher,可以接链式操作
   public var projectedValue: Publisher
}

ObservableObject 协议本质上是:

swift 复制代码
public protocol ObservableObject: AnyObject {
   // 编译器会自动合成这个,你的 @Published 属性改变时,它会发出信号
   var objectWillChange: ObservableObjectPublisher { get }
}

@ObservedObject 本质上是:View 订阅了 user.objectWillChange,只要它 emit,SwiftUI 就重新计算这个 View 的 body。

整个流程: user.score += 1@Published 的 setter 触发 → user.objectWillChange.send() → 订阅了它的 @ObservedObject 感知到 → SwiftUI 重新渲染对应的 View


@ObservedObject vs @StateObject

这是一个非常容易踩的坑:

@ObservedObject @StateObject
数据归属 不拥有,由外部传入 拥有,由这个 View 创建和持有
生命周期 跟随外部,不负责销毁 跟随 View,View 消失时销毁
典型场景 子 View 接收父 View 传来的模型 根 View 或顶层 View 创建模型

经验法则 :谁创建,谁用 @StateObject;谁接收,谁用 @ObservedObject


使用时需要关心的问题

  1. 只有 class 能用ObservableObjectAnyObject 的子协议,struct 和 enum 无法遵守,这套机制天生是为引用类型设计的。

  2. @Published 要精准 :不是所有属性都需要 @Published,只给真正需要驱动 UI 的属性加,滥加会导致不必要的 View 重渲染,影响性能。

  3. objectWillChange 是"将要改变" :SwiftUI 在属性改变之前 就会收到通知,你通常不需要手动调用它,但在某些手动控制的场景可以用 objectWillChange.send() 主动触发刷新。

复制代码
相关推荐
东坡肘子4 天前
被 Vibe 摧毁的版权壁垒,与开发者的新护城河 -- 肘子的 Swift 周报 #131
人工智能·swiftui·swift
用户79457223954135 天前
【DGCharts】iOS 图表渲染事实标准——8 种图表类型、高度可定制,3 行代码画出一条折线
swiftui·swift
用户79457223954139 天前
【Lottie】让设计稿上的动效直接"活"在 App 里
swiftui·swift
用户794572239541311 天前
【SnapKit】优雅的 Swift Auto Layout DSL 库
swiftui·swift
Mr_Tony11 天前
iOS / SwiftUI 输入法(键盘)布局处理总结(AI版)
ios·swiftui
东坡肘子11 天前
苹果的罕见妥协:当高危漏洞遇上“拒升”潮 -- 肘子的 Swift 周报 #130
人工智能·swiftui·swift
曾经我也有梦想18 天前
SwiftUI 如何使用 UIKit 组件
swiftui
东坡肘子18 天前
一墙之隔,不同的时空 -- 肘子的 Swift 周报 #129
人工智能·swiftui·swift
曾经我也有梦想19 天前
ViewModifier 和 圆角以及渐变色
swiftui
zhangjikuan8921 天前
SwiftUI 状态管理与架构实战
ios·架构·swiftui