iOS 17 Observable宏实现SwiftUI状态恢复的最优方案
用iOS 17 @Observable宏实现SwiftUI导航状态恢复的直接方案
核心思路
iOS 17的@Observable宏会自动为类生成变更追踪逻辑,无需手动处理ObservableObject的objectWillChange发布者。我们可以利用这一特性,直接通过视图的变更监听或模型内部的属性监听,实现导航数据到SceneStorage的同步,替代原有的异步流监听方案。
方案1:视图内监听模型整体变更
直接在视图中监听NavModel实例的变化,一旦模型属性更新就同步SceneStorage。
导航模型定义
import SwiftUI @Observable class NavModel { // 导航路径示例 var pathOne: [String] = [] var pathTwo: [Int] = [] // 生成用于存储的JSON数据 var jsonData: Data? { let combinedData = ["pathOne": pathOne, "pathTwo": pathTwo] return try? JSONSerialization.data(withJSONObject: combinedData) } }
视图实现
struct MainView: View { @SceneStorage("navigationData") private var storedData: Data? @State private var navModel = NavModel() var body: some View { NavigationStack(path: $navModel.pathOne) { // 你的导航视图内容 Text("Home") .navigationDestination(for: String.self) { item in Text("Detail: \(item)") } } .onAppear { // 从SceneStorage恢复导航状态 guard let data = storedData, let combined = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { return } navModel.pathOne = combined["pathOne"] as? [String] ?? [] navModel.pathTwo = combined["pathTwo"] as? [Int] ?? [] } .onChange(of: navModel) { _, _ in // 模型任何属性变化时,同步到SceneStorage storedData = navModel.jsonData } } }
方案2:细粒度监听具体路径属性
如果不想监听整个模型实例,可以单独监听导航路径的变化,减少不必要的触发:
struct MainView: View { @SceneStorage("navigationData") private var storedData: Data? @State private var navModel = NavModel() var body: some View { NavigationStack(path: $navModel.pathOne) { // 视图内容 } .onAppear { // 状态恢复逻辑同上 } .onChange(of: navModel.pathOne) { _ in updateStoredData() } .onChange(of: navModel.pathTwo) { _ in updateStoredData() } } private func updateStoredData() { let combinedData = ["pathOne": navModel.pathOne, "pathTwo": navModel.pathTwo] storedData = try? JSONSerialization.data(withJSONObject: combinedData) } }
方案3:模型内部处理属性变更
将状态同步逻辑封装在NavModel内部,视图只需监听最终的jsonData变化:
@Observable class NavModel { private(set) var jsonData: Data? var pathOne: [String] = [] { didSet { updateJsonData() } } var pathTwo: [Int] = [] { didSet { updateJsonData() } } private func updateJsonData() { let combinedData = ["pathOne": pathOne, "pathTwo": pathTwo] jsonData = try? JSONSerialization.data(withJSONObject: combinedData) } } // 视图中只需监听jsonData struct MainView: View { @SceneStorage("navigationData") private var storedData: Data? @State private var navModel = NavModel() var body: some View { NavigationStack(path: $navModel.pathOne) { // 视图内容 } .onAppear { // 状态恢复逻辑同上 } .onChange(of: navModel.jsonData) { newData in storedData = newData } } }
方案优势
相比原ObservableObject+异步流的实现,这些方案更简洁直观:
- 无需手动创建
objectWillChange的异步发布者和缓冲流 - 利用
@Observable自动生成的变更追踪,减少样板代码 - 可根据需求选择整体监听或细粒度监听,灵活性更高
内容的提问来源于stack exchange,提问作者dehlen
相关产品推荐
相关产品推荐

