具有已发布枚举的用户默认值
Posted
技术标签:
【中文标题】具有已发布枚举的用户默认值【英文标题】:Userdefaults with published enum 【发布时间】:2021-02-13 08:14:27 【问题描述】:尝试保存用户设置,但 UserDefaults 不起作用,Xcode 12.3,swiftui 2.0,当我重新加载我的应用程序时,我的设置没有更新为新值)
class PrayerTimeViewModel: ObservableObject
@Published var lm = LocationManager()
@Published var method: CalculationMethod = .dubai
didSet
UserDefaults.standard.set(method.params, forKey: "method")
self.getPrayerTime()
func getPrayerTime()
let cal = Calendar(identifier: Calendar.Identifier.gregorian)
let date = cal.dateComponents([.year, .month, .day], from: Date())
let coordinates = Coordinates(latitude: lm.location?.latitude ?? 0.0, longitude: lm.location?.longitude ?? 0.0)
var par = method.params
par.madhab = mashab
self.times = PrayerTimes(coordinates: coordinates, date: date, calculationParameters: par)
并查看.. 使用 AppStorage 进行更新
struct MethodView: View
@ObservedObject var model: PrayerTimeViewModel
@Environment(\.presentationMode) var presentationMode
@AppStorage("method", store: UserDefaults(suiteName: "method")) var method: CalculationMethod = .dubai
var body: some View
List(CalculationMethod.allCases, id: \.self) item in
Button(action:
self.model.objectWillChange.send()
self.presentationMode.wrappedValue.dismiss()
self.model.method = item
method = item
)
HStack
Text("\(item.rawValue)")
if model.method == item
Image(systemName: "checkmark")
.foregroundColor(.black)
【问题讨论】:
你在哪里加载来自UserDefaults
的值?您还应该显示CalculationMethod
的代码
我正在使用 AppStorage、checkOut、我的技能 swiftui Junior 更新我的视图)也许我没有取消
你还没有显示CalculationMethod
,那是什么?什么是method.params
?您还可以从两个不同的 UserDefaults
套件(标准和方法)中存储和检索。
CalculationMethod 是带case的枚举,所以这个枚举里面的params是var,他是切换case并返回一些参数,所以用户只能在SettingView中选择case,但我无法保存)跨度>
您似乎将参数保存在 userdefaults 中,但随后将枚举与您的 AppStorage 属性包装器一起使用。 CalculationMethod 的代码可以吗?
【参考方案1】:
你有两个问题。
首先,正如我在上面的评论中提到的,您正在为UserDefaults
使用两个不同的套件。这意味着您正在从两个不同的位置存储和检索。要么使用UserDefaults.standard
,要么使用您选择的套件UserDefaults(suitName: "method")
- 您不必使用套件,除非您计划与其他扩展共享您的默认设置,那么这样做是明智的。
其次,您在UserDefaults
中存储了错误的项目。您正在存储计算属性 params
而不是实际的枚举值。当您尝试检索该值时,它会失败,因为它没有得到预期的值并使用您设置的默认值。
这是一个简单的例子,展示了你可以做什么。有一个简单的枚举,它有一个原始值 (String
) 并符合 Codable
,它还有一个计算属性。这与您的枚举匹配。
我在ObservableObject
中添加了一个初始化程序。这用于在构造 Race
对象时从 UserDefaults 填充我发布的 Place
。
然后在我的ContentView
中,我根据按下按钮更新place
。这会更新 UI 并更新 UserDefaults
中的值。
这应该足以让您了解它的工作原理。
enum Place: String, Codable
case first
case second
case third
case notPlaced
var someComputedProperty: String
"Value stored: \(self.rawValue)"
class Race: ObservableObject
@Published var place: Place = .notPlaced
didSet
// Store the rawValue of the enum into UserDefaults
// We can store the actual enum but that requires more code
UserDefaults.standard.setValue(place.rawValue, forKey: "method")
// Using a custom suite
// UserDefaults(suiteName: "method").setValue(place.rawValue, forKey: "method")
init()
// Load the value from UserDefaults if it exists
if let rawValue = UserDefaults.standard.string(forKey: "method")
// We need to nil-coalesce here as this is a failable initializer
self.place = Place(rawValue: rawValue) ?? .notPlaced
// Using a custom suite
// if let rawValue = UserDefaults(suiteName: "method")?.string(forKey: "method")
// self.place = Place(rawValue: rawValue) ?? .notPlaced
//
struct ContentView: View
@StateObject var race: Race = Race()
var body: some View
VStack(spacing: 20)
Text(race.place.someComputedProperty)
.padding(.bottom, 20)
Button("Set First")
race.place = .first
Button("Set Second")
race.place = .second
Button("Set Third")
race.place = .third
附录:
因为枚举符合Codable
,所以可以使用AppStorage
来读取和写入属性。但是,这不会更新您的 ObservableObject
中的值,因此它们很容易不同步。最好有一个可以控制值的地方。在这种情况下,您的ObservableObject
应该是事实的来源,所有更新(读取和写入UserDefaults
)都应该通过那里进行。
【讨论】:
【参考方案2】:您在一个 UserDefaults 域中写入,但从另一个域中读取。假设您的意图是仅使用套件 UserDefaults,您应该在模型中更改一个,例如
@Published var method: CalculationMethod = .dubai
didSet
UserDefaults(suiteName: "method").set(method.params, forKey: "method")
self.getPrayerTime()
或者如果您想使用标准,那么只需使用带有默认构造函数的 AppStorage,例如
// use UserDefaults.standard by default
@AppStorage("method") var method: CalculationMethod = .dubai
【讨论】:
不工作(尝试查看我的 GitHub,链接在 cmets 中)以上是关于具有已发布枚举的用户默认值的主要内容,如果未能解决你的问题,请参考以下文章
具有符合 CaseIterable、RawRepresentable 的关联值的枚举