首页 > 解决方案 > @Published ObservedObjects SwiftUI 更新未发生

问题描述

@Published ObservedObjects SwiftUI 更新未发生

我创建了一个非常基本的 ObservableObject 应用程序,并且一些绑定已正确更新,而有些则没有。我一定错过了一些简单的东西。仅两个视图 - 开始视图和第二个视图。我只使用文本、按钮和切换——只是为了测试这个概念。

我想将启动属性值存储在 UserDefaults 中。那部分似乎工作正常。当我在第二页上进行更改时,它们会在该页面上更新,并且 UserDefaults 已正确写入。但是,在返回开始视图时,已发布的绑定不会更新。有趣的是,UserDefaults 已更新。

主视图仅显示绑定值和用户默认值。

开始视图:

import SwiftUI

struct ContentView: View {
    @State private var showUtilities = false
    @ObservedObject var userDefaultManager = UserDefaultsManager()

    var body: some View {
        NavigationView {
            VStack{
                Group { //group 1
                    Text("Published userDefaultManager.name:")
                    Text("\(UserUtilities().makeSubString(stringIn: self.userDefaultManager.name, count: 24))")
                        .padding(.bottom, 30)
                        .lineLimit(0)

                    Text("UserDefaults.standard.value:")
                    Text("\(UserUtilities().makeSubString(stringIn: UserDefaults.standard.value(forKey: "name") as! String, count: 24))")
                    .padding(.bottom, 30)
                    .lineLimit(0)

                    Text("Published userDefaultsManager.enableBiometrics:")
                    Text(String(self.userDefaultManager.enableBiometrics))
                        .padding(.bottom, 30)
                        .font(.headline)
                } //group 1

                Group { //group 2
                    Text("UserDefaults.standard.bool:")
                    Text(String(UserDefaults.standard.bool(forKey: AppDelegate.eb)))
                        .padding(.bottom, 30)
                        .font(.headline)
                    Button(action: {
                        self.showUtilities.toggle()
                    }) {
                        Text("Show Utilities")
                    }
                    .frame(width: 200)
                    .padding()
                    .font(.headline)
                }//group 2

            }//vstack
            .navigationBarTitle("Read the Values")
            .sheet(isPresented: $showUtilities) {
                UserUtilities()
            }
        }
    }
}

第二种观点:

import SwiftUI
import Combine

struct UserUtilities: View {
    @ObservedObject var userDefaultManager = UserDefaultsManager()

    var body: some View {
        NavigationView {
            VStack {
                Toggle(isOn: self.$userDefaultManager.enableBiometrics) {
                    Text("Enable Biometric Login")
                }
                .padding(EdgeInsets(top: 50, leading: 50, bottom: 30, trailing: 50))

                //this does not update
                Text("Published name is \(UserUtilities().makeSubString(stringIn: self.userDefaultManager.name, count: 24))")
                    .padding(EdgeInsets(top: 0, leading: 0, bottom: 30, trailing: 0))

                Text("UserDefaults name is \(UserUtilities().makeSubString(stringIn: UserDefaults.standard.value(forKey: "name") as! String, count: 24))")
                    .padding(EdgeInsets(top: 0, leading: 0, bottom: 30, trailing: 0))

                \\this does not update
                Text("Published enableBiometrics is "  + String(self.userDefaultManager.enableBiometrics) )

                Text("UserDefaults is " + String(UserDefaults.standard.bool(forKey: AppDelegate.eb)) )
                    .padding(.bottom, 20)

                Button(action: {
                    self.userDefaultManager.name = UUID().uuidString
                }) {
                    Text("Change the Published name")
                }
                .padding()
                .font(.headline)

            }
            .navigationBarTitle("User Utilities", displayMode: .inline)
        }
    }//body

    func makeSubString(stringIn: String, count: Int) -> String {
        if stringIn.count > count {
            let modString = stringIn.dropFirst(count)
            let returnString = String(modString)
            return returnString
        }
        return "can't get substring"
    }
}

我的用户默认管理器:

import SwiftUI
import Combine

class UserDefaultsManager: ObservableObject {
    @Published var name = UserDefaults.standard.value(forKey: "name") as! String {
           didSet {
               UserDefaults.standard.set(self.name, forKey: "name")
           }
    }

    @Published var enableBiometrics: Bool = UserDefaults.standard.bool(forKey: AppDelegate.eb) {
        didSet {
            UserDefaults.standard.set(self.enableBiometrics, forKey: AppDelegate.eb)
        }
    }
}

为了完整起见 - 在 AppDelegate 中:

static let eb = "enablebiometrics"
@ObservedObject var userDefaultManager = UserDefaultsManager()

在 didFinishLaunchingWithOptions 中:

    if UserDefaults.standard.value(forKey: AppDelegate.eb) == nil {
        UserDefaults.standard.set(false, forKey: AppDelegate.eb)
    }

    userDefaultManager.enableBiometrics = UserDefaults.standard.bool(forKey: AppDelegate.eb)

    if UserDefaults.standard.value(forKey: "name") == nil {
        UserDefaults.standard.set("set in AppDelegate", forKey: "name")
    }

    userDefaultManager.name = UserDefaults.standard.value(forKey: "name") as! String

任何指导将不胜感激。Xcode 11.3 (11C29)

标签: xcodeswiftuicombine

解决方案


您正在使用 UserDefaultsManager 的 2 个实例。仅实例化一个并将其传递给第二个视图或将其添加到环境 (@EnvironmentObject) 以在所有视图中访问它。

您可以在https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-environmentobject-to-share-data-between-views找到一个很好的例子。


推荐阅读