在 SwiftUI 中使用 UserDefaults 进行全局更新

Global Updates With UserDefaults In SwiftUI

我一直在使用@AppStorage 和UserDefaults 在SwiftUI 中进行更新。如果我对具有 @AppStorage 包装器的 vie 进行更改,则一切正常。我对如何在全球范围内开展这项工作感到困惑。

我使用的结构具有关联的计算属性和格式化程序。这个想法是检查用户默认值并将项目转换为磅或公斤。问题是当 UserDefaults 更新时,使用计算属性的视图不会更新。有没有办法创建一个全局更改来更新下面的 SecondaryView 中的 weightFormatted?

//权重结构

struct Weight {
var weight: Double
var weightFormatted: String {
return weightDecimalLbsOrKgFormatted2(weight)
}

//格式化方法

func weightDecimalLbsOrKgFormatted2(_ lbs: Double) -> String {
    if (!UserDefaults.standard.bool(forKey: "weightInKilograms")) {
        let weightString = decimalFormatterDecimal2(lbs)
        return weightString + "lbs"
        
    } else {
        let kg = toKg(lbs)
        let weightString = decimalFormatterDecimal2(kg)
        return weightString + "kg"
    }
}

//设置weightInKilograms的地方

struct AccountView: View {
    @AppStorage("weightInKilograms") var weightInKilograms = false

    let weight = Weight(weight: 9.0))
    
    var body: some View {
        VStack {
            Text(weight.weightFormatted)
            Toggle(isOn: $weightInKilograms) {
                        Text("Kilograms")
            }
        }
}
}

// 次要视图未更新

struct SecondaryView: View {

    let weight = Weight(weight: 9.0))
    
    var body: some View {
         Text(weight.weightFormatted)
}
}

你的问题是 weight 没有被任何状态包围。

在你的 AccountView 中,给 weight 一个 @State 包装器:

struct AccountView: View {
  
  @AppStorage("weightInKilograms") var weightInKilograms = false
  
  @State var weight = Weight(weight: 9.0))
  
  var body: some View {
    //...
  }
}

SecondaryView中,确保weight@Binding包裹:

struct SecondaryView: View {
  
  @Binding var weight: Weight
  
  var body: some View {
    // ...
  }
}

然后,在您的第一个视图中将 weight 作为 Binding<Weight> 变量传递给 SecondaryView

SecondaryView(weight: $weight)

Is there a way to create a global change that would update weightFormatted in SecondaryView below?

如果您希望进行 全局 更改,您应该考虑设置一个全局 EnvironmentObject:

class MyGlobalClass: ObservableObject {

  // Published variables will update view states when changed.
  @Published var weightInKilograms: Bool
  { get {
    // Get UserDefaults here
  } set {
    // Set UserDefaults here
  }}

  @Published var weight: Weight
}

如果您将 MyGlobalClass 的实例作为 EnvironmentObject 传递给您的主视图,然后再传递给您的辅助视图,则对全局实例中的属性所做的任何更改都将通过以下方式更新视图的状态@Published 包装器:

let global = MyGlobalClass()

/* ... */

// In your app's lifecycle, or where AccountView is instantiated
AccountView().environmentObject(global)
struct AccountView: View {
  @EnvironmentObject var global: MyGlobalClass

  var body: some View {
    // ...
    Text(global.weight.weightFormatted)
    // ...
    SecondaryView().environmentObject(global)
  }
}