首页 > 解决方案 > SwiftUI 中的可模拟 @AppStorage

问题描述

在开发 UIKit 应用程序时,UserDefaults通过定义协议并将所需的实现注入到UIViewController.

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 示例相同的灵活性?

标签: iosswiftswiftuimocking

解决方案


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

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

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

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

   // ... other code

推荐阅读