UserDefaults在SwiftUI中使用Toggle进行绑定 [英] UserDefaults Binding with Toggle in SwiftUI
问题描述
我正在尝试找出构建绑定到UserDefaults的简单设置屏幕的最佳方法.
基本上,我有一个Toggle,我想要:
Basically, I have a Toggle and I want:
- 每次更改此Toggle时都要保存的UserDefault值(UserDefault应该是事实的来源)
- 切换始终显示UserDefault的值
我已经看过许多SwiftUI WWDC会话,但是我仍然不确定如何使用Combine和SwiftUI中可用的不同工具来设置所有内容.我目前的想法是,我应该使用BindableObject,以便可以使用hat封装许多不同的设置.
I have watched many of the SwiftUI WWDC sessions, but I'm still not sure exactly how I should set everything up with the different tools that are available within Combine and SwiftUI. My current thinking is that I should be using a BindableObject so I can use hat to encapsulate a number of different settings.
我想我很亲密,因为它几乎可以按预期工作,但是行为却不一致.
I think I am close, because it almost works as expected, but the behavior is inconsistent.
当我在设备上构建并运行它时,我将其打开并打开Toggle,然后,如果我向上或向下滚动视图一点,则该开关将切换回关闭状态(好像实际上并没有在UserDefaults中保存该值)
When I build and run this on a device, I open it and turn on the Toggle, then if I scroll the view up and down a little the switch toggles back off (as if it's not actually saving the value in UserDefaults).
但是,如果我打开开关,请离开应用程序,然后稍后再打开,就像它记住了设置一样.
However, if I turn on the switch, leave the app, and then come back later it is still on, like it remembered the setting.
有什么建议吗?我发布此邮件的目的是希望它能对SwiftUI和Combine的新手有所帮助,因为我找不到与此主题相关的任何类似问题.
Any suggestions? I'm posting this in hopes it will help other people who are new to SwiftUI and Combine, as I couldn't find any similar questions around this topic.
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")
}
推荐答案
更新
------- iOS 14:-------
从iOS 14开始,现在有一种非常非常简单的方式来读写UserDefaults.
Starting iOS 14, there is now a very very simple way to read and write to UserDefaults.
使用名为 @AppStorage
这里是如何使用它:
import SwiftUI
struct ContentView : View {
@AppStorage("settingActivated") var settingActivated = false
var body: some View {
NavigationView {
Form {
Toggle(isOn: $settingActivated) {
Text("Setting Activated")
}
}.navigationBarTitle(Text("Settings"))
}
}
}
就是这样!这是如此简单,而且确实很简单.您的所有信息都将被保存并从UserDefaults中读取.
That's it! It is so easy and really straight forward. All your information is being saved and read from UserDefaults.
-------- iOS 13:---------
Swift 5.1发生了很多变化. BindableObject
已被完全弃用.此外, PassthroughSubject
中也发生了重大变化.
A lot has changed in Swift 5.1. BindableObject
has been completely deprecated. Also, there has been significant changes in PassthroughSubject
.
对于任何想使它起作用的人,下面是相同的工作示例.我已经重复使用了'gohnjanotis'的代码以使其变得简单.
For anyone wondering to get this to work, below is the working example for the same. I have reused the code of 'gohnjanotis' to make it simple.
import SwiftUI
import Combine
struct ContentView : View {
@ObservedObject var settingsStore: SettingsStore
var body: some View {
NavigationView {
Form {
Toggle(isOn: $settingsStore.settingActivated) {
Text("Setting Activated")
}
}.navigationBarTitle(Text("Settings"))
}
}
}
class SettingsStore: ObservableObject {
let willChange = PassthroughSubject<Void, Never>()
var settingActivated: Bool = UserDefaults.settingActivated {
willSet {
UserDefaults.settingActivated = newValue
willChange.send()
}
}
}
extension UserDefaults {
private struct Keys {
static let settingActivated = "SettingActivated"
}
static var settingActivated: Bool {
get {
return UserDefaults.standard.bool(forKey: Keys.settingActivated)
}
set {
UserDefaults.standard.set(newValue, forKey: Keys.settingActivated)
}
}
}
这篇关于UserDefaults在SwiftUI中使用Toggle进行绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!