在 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 变量?