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

Posted

技术标签:

【中文标题】在 SwiftUI 中使用 UserDefaults 进行全局更新【英文标题】:Global Updates With UserDefaults In SwiftUI 【发布时间】:2021-06-25 23:33:37 【问题描述】:

我一直在使用 @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)


【问题讨论】:

【参考方案1】:

您的问题是 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)

有没有办法创建一个全局更改来更新下面 SecondaryView 中的 weightFormatted?

如果您希望进行全局更改,您应该考虑设置一个全局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)
  

【讨论】:

非常感谢您的回复。我正在添加此信息和一些组合代码以更正此问题。

以上是关于在 SwiftUI 中使用 UserDefaults 进行全局更新的主要内容,如果未能解决你的问题,请参考以下文章

Swiftui 如何在 foreach 循环中对整行使用 Tap Gesture

SwiftUI:如何使用 UserDefaults 持久化 @Published 变量?

如何从 Swift 类中检索目标 C 类中的 Userdefault?

使用 UserDefault 快速存储和检索数组数据

如何在 UserDefault 中存储推送通知警报消息?

如何在 userdefault 中存储和检索数据? (例如:结构数组)