@Published ObservedObjects SwiftUI 更新未发生

@Published ObservedObjects SwiftUI Updates not Happening

@Published ObservedObjects SwiftUI 更新未发生

我创建了一个非常基本的 ObservableObject 应用程序并且更新了一些绑定 正确的,有些不是。我一定错过了一些简单的东西。只有两个视图 - 开始视图和第二个视图。我只使用 Text、Button 和 Toggle - 只是为了测试 这个概念。

我想在 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

如有任何指导,我们将不胜感激。 Xcode11.3 (11C29)

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

您可以在 https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-environmentobject-to-share-data-between-views.

找到如何执行此操作的一个很好的示例

在 UserUtilities 中,将 @ObservedObject var userDefaultManager = UserDefaultsManager() 更改为 @Binding var userDefaultManager: UserDefaultsManager,并将 ContentView 中的 userDefaultManager variable 作为参数传递给 UserUtilities