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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 05:15:58