Swift中跨view视图组件实现全局状态共享的方式汇总

写前端习惯了,比较喜欢使用Pinia那种全局状态共享的功能,就尝试怎么实现,实现方式大概有四种,这四种都是比较简单的,分别是使用 @StateObject+@EnvironmentObject 和 @StateObject + @ObservedObject,还有@AppStorage 和 单利模式的ObservableObject这四种。

@StateObject+@EnvironmentObject方式

这种方式需要通过环境变量传递给子视图,并且子视图不持有这个数据状态

全局状态视图:

Swift 复制代码
// 数据状态同步管理
class CounterModel: ObservableObject {
    @Published var count: Int = 0
}

父视图:

Swift 复制代码
struct ContentView: View {
    @StateObject private var counter = CounterModel()

    var body: some View {
        VStack(spacing: 20) {
            Text("父组件:当前计数:\(counter.count)")
                .font(.title)
            // 将 counter 传递给子组件
            ChildView()
                .environmentObject(counter)
        }
        .padding()
    }
}

子视图:也可以通过onChange监听数据变化

Swift 复制代码
struct ChildView: View {
    @EnvironmentObject var counter: CounterModel

    var body: some View {
        Button("子组件按钮 +1") {
            counter.count += 1
        }
        .padding()
        .background(.blue.opacity(0.2))
        .cornerRadius(10)
        .onChange(of: counter.count) { _, _ in
            print("count change")
        }
    }
}

@StateObject + @ObservedObject方式

这种方式需要通过父视图传递给子视图,并且子视图不持有这个数据状态

全局状态视图:

Swift 复制代码
// 数据状态同步管理
class CounterModel: ObservableObject {
    @Published var count: Int = 0
}

父视图:

Swift 复制代码
struct ContentView: View {
    @StateObject private var counter = CounterModel()

    var body: some View {
        VStack(spacing: 20) {
            Text("父组件:当前计数:\(counter.count)")
                .font(.title)
            // 将 counter 传递给子组件
            ChildView(counter: counter)
        }
        .padding()
    }
}

子视图:

Swift 复制代码
struct ChildView: View {
    @ObservedObject var counter: CounterModel

    var body: some View {
        Button("加 1") {
            counter.count += 1
        }
        .onChange(of: counter.count) { _, _ in
            print("counter 变化")
        }
    }
}

@AppStorage方式

使用AppStorage的方式适合存储一些轻量数据,小量简单数据(如登录状态、语言、主题)。所有界面自动同步,不需要 ObservableObject,也支持使用 onChange 监听。并且数据是持久化存储在本地的,后面重启会恢复之前的数值。

Swift 复制代码
struct ChildView: View {
    // 接收环境对象(跨组件共享的数据)
    @AppStorage("name") var name = ""

    var body: some View {
        Button("子组件按钮 +1") {
            name += "1024小神"
        }
        .padding()
        .background(.blue.opacity(0.2))
        .cornerRadius(10)
        .onChange(of: name) { _, _ in
            print("name change")
        }
    }
}

单利模式的ObservableObject

创建一个全局的单实例类,用于全局的状态管理:

Swift 复制代码
// 单利模式全局状态
class GlobalState: ObservableObject {
    // 创建全局共享静态属性
    static let shared = GlobalState()
    // 防止外部创建
    private init() {}
    // 共享的数据
    @Published var count: Int = 0
}

然后在任意view中都可以使用:并支持onChange监听

Swift 复制代码
struct AnotherChildView: View {
    // 全局状态
    @ObservedObject var globalState = GlobalState.shared

    var body: some View {
        Text("另一个子组件:当前计数:\(globalState.count)")
            .font(.headline)
            .padding()
            .onChange(of: globalState.count) { _, _ in
                print("globalState.count发生了变化")
            }
    }
}
相关推荐
茶底世界之下6 小时前
Metal 冷启动并发下,Pipeline Cache 为什么必须合并在途编译
ios·swift
weixin_403810137 小时前
用 Python 调 EasyClick iOS 免越狱脚本:开放接口对接步骤与参数
ios·iphone
weixin_403810139 小时前
EasyClick iOS 免越狱自动化脚本怎么写:从环境判断到跑通第一个脚本
运维·ios·自动化
weixin_4038101310 小时前
不用越狱也能批量控制 iPhone:EasyClick iOS 免越狱脚本实战
ios·iphone
weixin_4038101311 小时前
iOS 自动化脚本怎么输入文字:代理、输入法与快捷指令三级方案
运维·ios·自动化
黑科技iOS上架1 天前
双引擎解决oc/swift开发引用加固难题
开发语言·ios·swift·审核·ios混淆·执行程序差异化
wechatbot8881 天前
企微第三方自动化开发:原生能力无阉割 API 开放平台介绍
后端·ios·微信·企业微信·ai编程·ipad
黑科技iOS上架1 天前
iOS framework/dylib动态库定向加固实战
macos·ios·objective-c·cocoa·审核·ios混淆·执行程序差异化
传奇开心果编程2 天前
【现代声明式UI学与练】第1课 从命令式UI到声明式UI
学习·flutter·ui·swiftui·react·android jetpack
可乐鸡翅yeah_2 天前
fmp4 碎片 MP4 格式 HLS 流,和传统 TS 分片有什么不一样
开发语言·javascript·ios·音视频·safari·m3u8·m3u8在线播放