SwiftUI 中的可模拟 @AppStorage

Posted

技术标签:

【中文标题】SwiftUI 中的可模拟 @AppStorage【英文标题】:Mockable @AppStorage in SwiftUI 【发布时间】:2020-12-29 14:39:38 【问题描述】:

在开发 UIKit 应用程序时,很容易通过定义协议并将所需的实现注入到 UIViewController 中来模拟 UserDefaults

protocol Defaults 
    var numberOfHandsPlayed: Int  get set 


struct AppDefaults: Defaults 
    static let shared = AppDefaults()
    private let userDefaults = UserDefaults.standard

    struct Keys 
        private init() 
        static let numberOfHandsPlayed = "numberOfHandsPlayed"
    


    var numberOfHandsPlayed: Int 
        get 
            userDefaults.integer(forKey: Keys.numberOfHandsPlayed)
        
        set(numberOfHandsPlayed) 
            userDefaults.setValue(numberOfHandsPlayed, forKey: Keys.numberOfHandsPlayed)
        
    


struct MockDefaults: Defaults 
    var numberOfHandsPlayed: Int 
    get 
        // mocking behaviour
    
    set(numberOfHandsPlayed) 
        // mocking behaviour
    


class PracticeViewController: UIViewController 
    private var defaults: Defaults?
    // defaults can be set to MockDefaults or AppDefaults

但现在有了 SwiftUI,我可以使用 @AppStorage 属性包装器执行以下操作:

@AppStorage("numberOfHandsPlayed") var numberOfHandsPlayed: Int = 3

在 SwiftUI 中是否有一个干净的解决方案来模拟这个属性包装器并具有与我的 UIKit 示例相同的灵活性?

【问题讨论】:

【参考方案1】:

AppStorage 允许指定要使用的存储(默认情况下为标准UserDefaults),因此可以将此功能用于您的目的。

一种可能的方法是对标准用户默认设置进行子类化,然后在需要时/在需要时对其进行模拟。

class MyUserDefaults: UserDefaults 
    // override/add anything needed here


struct DemoView: View 
    @AppStorage("numberOfHandsPlayed", store: MyUserDefaults()) var numberOfHandsPlayed: Int = 3

   // ... other code

【讨论】:

以上是关于SwiftUI 中的可模拟 @AppStorage的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI @AppStorage 不在函数中刷新

SwiftUI:绑定到@AppStorage

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

SwiftUI - AppStorage 不适用于 GeometryReader

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

SwiftUI:你可以将 AppStorage 与解码的 json 一起使用吗?