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

如何在同一SwiftUI macOS应用的多窗口间共享状态

Mac平台SwiftUI多窗口状态共享方案

问题描述

我希望在Mac平台的同一SwiftUI应用的多个窗口之间共享状态。根据文档说明,@State和@StateObject无法实现状态共享,我的示例代码也验证了这一点。请问该如何实现两个窗口间的状态共享?

示例代码:

@main
struct TM_window_TestApp_2: App {
  @State var state: String?
  @State var selectedInSub: Int?
  @StateObject var stateObject = SimpleStateObject()
  
  var body: some Scene {
    WindowGroup {
      VStack{
        SubView(selected: $selectedInSub)
        Text("\(selectedInSub == nil ? \"nothing selected\" : selectedInSub!.formatted())")
        Text("------------")
        Text("shared State: ??")
        Text(stateObject.s)
        Text("\(state == nil ? \"nil\" : state!)")
        Button("change StateObject"){stateObject.s.append("_x")}
        Button("change State"){if state == nil {
          state = "state"} else{
            state?.append("_y")
          }
        }
      }
    }
  }
}

struct SubView: View {
  @Binding var selected: Int?
  @State var selectedLocal : Int?
  var values = [1,2,3,4,5,6,7]
  
  var body: some View {
    NavigationView{
      List(values, id: \.self, selection: $selectedLocal) { val in
        Text("\(val)")
      }
    }    
  }
}


class SimpleStateObject: ObservableObject {
  @Published var s = "stateObject"
}

有趣的是,在iPad应用的分屏模式下,@State和@StateObject是可以实现状态共享的。

实现方案

在Mac SwiftUI中,多窗口无法共享@State/@StateObject的核心原因是:每个窗口都是WindowGroup创建的独立视图实例,会各自初始化自己的状态对象。要实现共享,需让状态脱离单个窗口的生命周期,成为应用级全局实例,以下是两种常用方案:

1. 使用@AppStorage(适合轻量持久化状态)

如果状态是字符串、数字这类基础类型,且需要持久化,@AppStorage直接绑定系统存储,天然支持多窗口同步:

@main
struct TM_window_TestApp_2: App {
    @AppStorage("sharedState") var state: String?
    @AppStorage("selectedValue") var selectedInSub: Int?
    
    var body: some Scene {
        WindowGroup {
            VStack{
                SubView(selected: $selectedInSub)
                Text("\(selectedInSub == nil ? "nothing selected" : selectedInSub!.formatted())")
                Text("------------")
                Text("shared State: ??")
                Text("\(state == nil ? "nil" : state!)")
                Button("change State"){
                    if state == nil {
                        state = "state"
                    } else {
                        state?.append("_y")
                    }
                }
            }
        }
    }
}

2. 全局单例+@ObservedObject(适合复杂状态对象)

对于自定义的ObservableObject,通过全局单例或App级静态属性确保所有窗口共用同一个实例:

方式一:全局单例

class SimpleStateObject: ObservableObject {
    static let shared = SimpleStateObject() // 全局单例
    @Published var s = "stateObject"
}

@main
struct TM_window_TestApp_2: App {
    @State var state: String?
    @State var selectedInSub: Int?
    @ObservedObject var stateObject = SimpleStateObject.shared // 引用单例
    
    var body: some Scene {
        WindowGroup {
            VStack{
                SubView(selected: $selectedInSub)
                Text("\(selectedInSub == nil ? "nothing selected" : selectedInSub!.formatted())")
                Text("------------")
                Text("shared State: ??")
                Text(stateObject.s)
                Text("\(state == nil ? "nil" : state!)")
                Button("change StateObject"){stateObject.s.append("_x")}
                Button("change State"){
                    if state == nil {
                        state = "state"
                    } else {
                        state?.append("_y")
                    }
                }
            }
        }
    }
}

方式二:App层级静态属性

class SimpleStateObject: ObservableObject {
    @Published var s = "stateObject"
}

@main
struct TM_window_TestApp_2: App {
    static let stateObject = SimpleStateObject() // App级静态实例
    @State var state: String?
    @State var selectedInSub: Int?
    @ObservedObject var sharedStateObject = TM_window_TestApp_2.stateObject
    
    var body: some Scene {
        WindowGroup {
            VStack{
                SubView(selected: $selectedInSub)
                Text("\(selectedInSub == nil ? "nothing selected" : selectedInSub!.formatted())")
                Text("------------")
                Text("shared State: ??")
                Text(sharedStateObject.s)
                Text("\(state == nil ? "nil" : state!)")
                Button("change StateObject"){sharedStateObject.s.append("_x")}
                Button("change State"){
                    if state == nil {
                        state = "state"
                    } else {
                        state?.append("_y")
                    }
                }
            }
        }
    }
}

补充说明:iPad分屏的特殊情况

iPad分屏模式下,多个窗口属于同一个视图层级的分支,共享App结构体的状态实例,因此@State/@StateObject可以直接共享;而Mac的多窗口是完全独立的视图实例,各自初始化状态,所以无法直接共享。

内容的提问来源于stack exchange,提问作者mica

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 22:57:42