SwiftUI中如何实现单例模式的@ObservedObject?
核心问题:你的单例根本没实现“唯一实例”
你第一个版本的static var shared: AppState { AppState() }每次调用都会创建新的AppState实例,父视图和子视图拿到的是两个完全独立的对象——父视图修改showLabels时,子视图的对象根本没变化,自然不会触发刷新。
第二个版本用StateHolder的思路也走偏了:static private var _stateHolder: StateHolder { StateHolder() }同样是每次访问都会创建新的StateHolder,里面的@StateObject也会跟着初始化新的AppState,还是没做到真正的单例共享。
正确的单例实现方式
要确保AppState只有一个实例,最直接可靠的方式是用static let shared(Swift中static let默认是懒加载且线程安全的),同时私有化构造器防止外部创建新实例:
class AppState: ObservableObject { @Published var showLabels = false // 真正的单例:全局唯一,仅初始化一次 static let shared = AppState() // 私有化构造器,禁止外部手动创建实例 private init() {} }
视图中正确使用方式
在视图里直接用@ObservedObject引用这个唯一单例即可:
struct IdentityPanel: View { // 绑定全局唯一的AppState实例 @ObservedObject var appState = AppState.shared @State private var name = "" var body: some View { Section("Identity") { if appState.showLabels { Text("Enter your Name here:") } TextField("Name", text: $name) } } } struct SingletonAppState: View { @ObservedObject var appState = AppState.shared var body: some View { Form { Toggle("Show Labels", isOn: $appState.showLabels) IdentityPanel() } } }
这样父视图和子视图访问的是同一个AppState实例,当showLabels变化时,所有订阅该实例的视图都会收到通知并自动刷新。
底层逻辑说明
SwiftUI中,@ObservedObject的作用是让视图订阅ObservableObject的objectWillChange发布者。只有当多个视图订阅同一个实例时,实例的@Published属性变化才会同步通知到所有关联视图。你的错误根源在于每次获取shared都生成新实例,导致不同视图订阅的是完全独立的对象,状态自然无法同步。
不需要用StateHolder这类复杂方式,static let本身就能保证单例的唯一性和懒加载特性,私有化构造器还能避免外部意外创建新实例。
内容的提问来源于stack exchange,提问作者Curious Jorge

