SwiftUI视图修改单例模式
SwiftUI视图修改单例模式

SwiftUI视图修改单例模式

在 SwiftUI 中,使用单例模式的情况下,即使类遵循 ObservableObject 以及参数的属性包装器为 @Published,如果视图中没有使用 @StateObject 或 @ObservedObject 来观察它,视图就不会更新。

class TemporaryData: ObservableObject {
    static var shared = TemporaryData()
    private init() {}
    @Published var completeCompression = false  // 完成压缩,false为未完成,true为完成
    @Published var selectedView:SelectedView = .compression
}

在SwiftUI中,尝试修改单例模式 TemporaryData.shared 的属性:

struct ContentView: View {
    @State private var selectedView = TemporaryData.shared.selectedView
    var body: some View {
        Button("修改单例属性"){
            selectedView = .compression
        }

发现在当前视图中修改成功,当前视图的参数可以根据 selectedView变化发生改变,但实际上并没有修改TemporaryData.shared的属性。

问题原因

这是因为,当我在ContentView中声明:

@State private var selectedView = TemporaryData.shared.selectedView

这意味着创建了一个与 TemporaryData.shared 无关的本地副本,修改的是本地的 selectedView,而不是 TemporaryData.shared 的 selectedView。

解决方案

如果要监听并修改TemporaryData.shared中的属性,可以使用以下两种方案:

方案1:使用@ObservedObject

struct ContentView: View {
    @ObservedObject private var selectedView = TemporaryData.shared.selectedView
    var body: some View {
        Button("修改单例属性"){
            selectedView = .compression
        }

将 @State改为 @ObservedObject。

@ObservedObject 要求对象符合ObservableObject协议,所以不能使用属性,否则就会报错:

Generic struct 'ObservedObject' requires that 'SelectedView' conform to 'ObservableObject'

因此,需要将TemporaryData.shared.selectedView属性修改为TemporaryData.shared单例。

@State private var selectedView = TemporaryData.shared.selectedView // 修改前
@ObservedObject private var selectedView = TemporaryData.shared // 修改后

这样就可以通过修改 selectedView 实现修改 TemporaryData.shared 的目的。

方案2:使用 @EnvironmentObject

在入口文件注入环境对象:

// App 启动时注入环境对象
@main
struct ImageSlimApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(TemporaryData.shared)
        }
    }
}

在视图中使用 @EnvironmentObject引入环境对象:

struct ContentView: View {
    @EnvironmentObject var selectedView = TemporaryData
    var body: some View {
        Button("修改单例属性"){
            selectedView = .compression
        }

这两个方案都可以解决修改单例模式属性,从而实现所有视图的监听和数据共享。

总结

在SwiftUI中使用单例模式,如果想要在其他视图中访问,可以直接获取单例数据。例如:

Text("\(TemporaryData.shared.selectedView)")

但是,如果需要修改单例模式的数据,就需要使用 @ObservedObject 或 @EnvironmentObject,通过观察对象或环境对象获取单例模式,从而实现对于单例模式的修改。

扩展知识

@StateObject可以观察单例模式么?

如果使用 @StateObject,实际上也可以观察到单例属性:

struct ContentView: View {
    @StateObject var selectedView = TemporaryData.shared
    var body: some View {
        Button("修改单例属性"){
            selectedView = .compression
        }

@StateObject适用于首次创建该对象的视图,当前视图(自己)管理,如果希望SwiftUI创建并管理对象,可以使用 @StateObject。

@ObservedObject适用于外部传入的 ObservableObject,生命周期由父视图或其他外部管理,例如父视图已经创建好,只是子视图拿来观察。

所以,当使用 @StateObject 观察单例模式时:

@StateObject var data = TemporaryData.shared

这表示当前视图拥有并管理这个对象的生命周期,SwiftUI只会在视图初始化时创建一次对象,而对象重建时,对象并不会重新创建。

而 TemporaryData.shared 实际上是已经存在的,所以 @StateObject 的管理创建在这里没有意义。

相比之下,ObservedObject则用于观察外部对象,比如父视图传入的 model,或像这种单例共享对象。

总的来说,@StateObject用于首次创建并管理的对象,@ObservedObject用于外部传入的对象,所以单例模式更适合后者。

相关文章

Swift控制全局的单例模式:https://fangjunyu.com/2024/10/19/swift%e6%8e%a7%e5%88%b6%e5%85%a8%e5%b1%80%e7%9a%84%e5%8d%95%e4%be%8b%e6%a8%a1%e5%bc%8f/

   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注