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

50 阅读2分钟

大家好,我的开源项目PakePlus可以将网页/Vue/React项目打包为桌面/手机应用并且小于5M只需几分钟,官网地址:pakeplus.com

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

@StateObject+@EnvironmentObject方式

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

全局状态视图:

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

父视图:

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监听数据变化

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方式

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

全局状态视图:

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

父视图:

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()
    }
}

子视图:

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 监听。并且数据是持久化存储在本地的,后面重启会恢复之前的数值。

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

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

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

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


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发生了变化")
            }
    }
}

大家好,我是1024小神,技术群 / 私活群 / 股票群 或 交朋友 都可以私信我。 如果你觉得本文有用,一键三连 (点赞、评论、关注),就是对我最大的支持~