@Published ObservedObjects SwiftUI更新未发生

时间:2020-01-14 06:58:52

标签: xcode swiftui combine

@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"
    }
}

我的UserDefault Manager:

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)

2 个答案:

答案 0 :(得分:4)

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

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

答案 1 :(得分:2)

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