UserDefaults在SwiftUI中使用Toggle进行绑定 [英] UserDefaults Binding with Toggle in SwiftUI

查看:70
本文介绍了UserDefaults在SwiftUI中使用Toggle进行绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试找出构建绑定到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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆