我试图找出构建绑定到 UserDefaults 的简单设置屏幕的最佳方法。
基本上,我有一个切换,我想要:
- 更改此切换时要保存的 UserDefault 值(UserDefault 应该是事实的来源)
- 切换为始终显示 UserDefault 的值
我已经观看了许多 SwiftUI WWDC 会议,但我仍然不确定应该如何使用 Combine 和 SwiftUI 中提供的不同工具来设置所有内容。我目前的想法是我应该使用 BindableObject,这样我就可以使用 hat 来封装许多不同的设置。
我想我很接近,因为它几乎可以按预期工作,但行为不一致。
当我在设备上构建并运行它时,我打开它并打开 Toggle,然后如果我稍微上下滚动视图,开关就会切换回关闭(好像它实际上并没有保存 UserDefaults 中的值)。
但是,如果我打开开关,离开应用程序,然后稍后再回来,它仍然处于打开状态,就像它记住了设置一样。
有什么建议么?我发布这篇文章是希望它能帮助其他刚接触 SwiftUI 和 Combine 的人,因为我在这个主题上找不到任何类似的问题。
import SwiftUI
import Combine
struct ContentView : View {
@ObjectBinding var settingsStore = SettingsStore()
var body: some View {
NavigationView {
Form {
Toggle(isOn: $settingsStore.settingActivated) {
Text("Setting Activated")
}
}
}.navigationBarTitle(Text("Settings"))
}
}
class SettingsStore: BindableObject {
var didChange = NotificationCenter.default.publisher(for: .settingsUpdated).receive(on: RunLoop.main)
var settingActivated: Bool {
get {
UserDefaults.settingActivated
}
set {
UserDefaults.settingActivated = newValue
}
}
}
extension UserDefaults {
private static var defaults: UserDefaults? {
return UserDefaults.standard
}
private struct Keys {
static let settingActivated = "SettingActivated"
}
static var settingActivated: Bool {
get {
return defaults?.value(forKey: Keys.settingActivated) as? Bool ?? false
}
set {
defaults?.setValue(newValue, forKey: Keys.settingActivated)
}
}
}
extension Notification.Name {
public static let settingsUpdated = Notification.Name("SettingsUpdated")
}