使用 @AppStorage 进行设置的 SwiftUI 最佳实践:如何在加载 @AppStorage 之前读取 UserDefaults?

Posted

技术标签:

【中文标题】使用 @AppStorage 进行设置的 SwiftUI 最佳实践:如何在加载 @AppStorage 之前读取 UserDefaults?【英文标题】:SwiftUI best practice for using @AppStorage for settings: How to read the UserDefaults before the @AppStorage loaded? 【发布时间】:2021-02-22 00:09:04 【问题描述】:

我使用@AppStorage 在设置视图中保存一些首选项,就像苹果推荐的那样:https://developer.apple.com/documentation/swiftui/settings

我还有一个主窗口,它会在用户打开设置视图之前读取一些首选项,然后似乎我会读取“错误的”UserDefaults,因为预期值未写入 UserDefaults,因为尚未加载设置视图。

例如:

// Settings view
struct SettingsView: View 
   @AppStorage("x") var x = 5  // give preference a default value
   ...


// Main view
struct MainView: View 

    func foo() 
        let x = UserDefaults.standard.double(forKey: "x")
        // x is not the default value I expect
    

我知道的可能解决方案:

    在应用启动时,检查 UserDefaults 是否为 nil,如果是,则使用默认值写入它们 读取 UserDefaults 时,检查 UserDefaults 是否为 nil,如果是,则改为读取默认值。

有没有更好的处理方法?谢谢!

【问题讨论】:

【参考方案1】:

UserDefaults 提供了一个名为register 的方法,它使用“默认”(没有双关语)值加载它。这些值仅在实际存储在UserDefaults 中的那些键没有任何值的情况下使用。

我发现在应用启动时使用我的 AppDelegate 的应用包中的 plist 中的值填充它很有用(例如在didFinishLaunchingWithOptions 中——如果使用 SwiftUI 生命周期,您仍然可以这样做:SwiftUI app life cycle ios14 where to put AppDelegate code?) :

if let prefs = Bundle.main.path(forResource: "defaults", ofType: "plist"), 
    let dict = NSDictionary(contentsOfFile: prefs) as? [String : Any] 
  UserDefaults.standard.register(defaults: dict)

https://developer.apple.com/documentation/foundation/userdefaults/1417065-register

来自文档:

注册域的内容没有写入磁盘; 您需要在每次应用程序启动时调用此方法。您可以在应用程序的 Resources 目录中放置一个 plist 文件,然后使用从该文件中读取的内容调用 register(defaults:)。

使用这个系统,您不必费心检查自己的nil 值并决定是否加载默认值。而且,当您从 UserDefaults 读取支票时,您会在其中看到预填充的值。

【讨论】:

以上是关于使用 @AppStorage 进行设置的 SwiftUI 最佳实践:如何在加载 @AppStorage 之前读取 UserDefaults?的主要内容,如果未能解决你的问题,请参考以下文章

如何让@AppStorage 在 MVVM / SwiftUI 框架中工作?

如何在 ViewModel 中使用带有自定义类型和 @Published 的 @AppStorage?

使用非零值初始化可选的 @AppStorage 属性

SwiftUI @AppStorage 不在函数中刷新

AppStorage 与 CoreData

SwiftUI:绑定到@AppStorage