使用 @Published 和 ObservableObject
核心概念
ObservableObject 协议
- 定义:
ObservableObject是 Combine 框架中的协议,用于标记类对象为可观察对象 - 特点:
- 必须继承自
AnyObject(即必须是 class 类型) - 自动合成
objectWillChange发布者 - 适用于管理应用状态和业务逻辑
- 必须继承自
@Published 属性包装器
- 作用:自动为属性创建发布者,当属性值改变时通知订阅者
- 特性:
- 只能用于
ObservableObject内部的属性 - 隐式调用
objectWillChange.send() - 支持值类型和引用类型数据
- 只能用于
实现机制
基本使用模式
class UserViewModel: ObservableObject {
@Published var username: String = ""
@Published var isLoggedIn: Bool = false
}
数据绑定原理
- 当
@Published属性变化时触发更新 - SwiftUI 视图通过
@ObservedObject或@StateObject监听变化 - 系统自动比较视图的依赖项决定是否需要重绘
实际应用
与视图的绑定方式
struct ProfileView: View {
@ObservedObject var viewModel: UserViewModel
var body: some View {
TextField("Username", text: $viewModel.username)
Toggle("Logged In", isOn: $viewModel.isLoggedIn)
}
}
生命周期管理
| 属性包装器 | 适用场景 | 生命周期 |
|---|---|---|
@ObservedObject | 外部传入的 ViewModel | 跟随父视图更新 |
@StateObject | 视图自己创建的 ViewModel | 与视图生命周期一致 |
高级技巧
手动触发更新
class DataLoader: ObservableObject {
var items: [String] = [] {
willSet { objectWillChange.send() }
}
func loadData() {
// 非@Published属性需要手动通知
items = fetchData()
}
}
性能优化建议
- 避免在 ViewModel 中过度使用
@Published - 对复杂数据结构考虑使用
@Published private(set) - 将相关属性分组到嵌套的
ObservableObject中
常见问题解决方案
更新不触发的问题排查
- 检查类是否遵循
ObservableObject - 确认视图使用了正确的属性包装器
- 验证是否在主线程更新属性
循环引用预防
class SafeViewModel: ObservableObject {
@Published var data: [Item] = []
// 使用弱引用打破循环
weak var delegate: SomeDelegate?
// 或者使用非持有引用
var onUpdate: (() -> Void)?
}
最佳实践提示:对于简单的状态管理,优先考虑
@State和@Binding;当涉及复杂业务逻辑时再使用ObservableObject和@Published的组合。
