简体   繁体   English

我如何实现一个通用结构来管理 Swift 中 UserDefaults 的键值对?

[英]How can I implement a generic struct that manages key-value pairs for UserDefaults in Swift?

How would one implement a struct that manages UserDefaults mappings in Swift?如何在 Swift 中实现一个管理 UserDefaults 映射的结构? Right now I have some computed properties a, b, c, d of different types and corresponding keys that look like this:现在我有一些不同类型的计算属性 a、b、c、d 和相应的键,如下所示:

enum UserDefaultsKeys {
    a_key
    b_key
    ...
}
var a: String {
    get { UserDefaults.standard.string(forKey: UserDefaultsKeys.a_key.rawValue) }
    set { UserDefaults.standard.set(newValue, forKey: UserDefaultsKeys.a_key.rawValue) }
}
var b: Int {
    get { UserDefaults.standard.integer(forKey: UserDefaultsKeys.b_key.rawValue) }
    set { UserDefaults.standard.set(newValue, forKey: UserDefaultsKeys.b_key.rawValue) }
}
...

What I would like to achieve instead is to implement a struct that has a key of type String and a generic type value.相反,我想要实现的是实现一个结构,该结构具有 String 类型的键和泛型类型值。 The value get function should - depending on its type - chose wether to use UserDefaults.standard.string or UserDefaults.standard.integer so that I can just create a DefaultsVar with some key and everything else is managed automatically for me.值 get function 应该——根据它的类型——选择使用UserDefaults.standard.stringUserDefaults.standard.integer这样我就可以用一些键创建一个 DefaultsVar 并且其他一切都为我自动管理。 What I have so far is this:我到目前为止是这样的:

struct DefaultsVar<T> {
    let key: String
    var value: T {
        get {
            switch self {
                case is String: return UserDefaults.standard.string(forKey: key) as! T
                case is Int: return UserDefaults.standard.integer(forKey: key) as! T
                default: return UserDefaults.standard.float(forKey: key) as! T
            }
        }
        set { UserDefaults.standard.set(newValue, forKey: key) }
    }
}

I get the following error: "Cast from DefaultsVar to unrelated Type 'String' always fails. I am completely new to swift (and relatively new to programming) and don't really understand how to implement this the right way - or if this is even an approach that would be considered a good practice. Could someone please shine some light on this?我收到以下错误:“从 DefaultsVar 转换为不相关的类型‘String’总是失败。我对 swift 是全新的(并且对编程来说相对较新)并且真的不明白如何以正确的方式实现它 - 或者如果这是即使是一种被认为是良好做法的方法。有人可以对此有所了解吗?

Thank you in advance!先感谢您!

You can use a custom您可以使用自定义

Property wrapper:属性包装器:

@propertyWrapper
struct UserDefaultStorage<T: Codable> {
    private let key: String
    private let defaultValue: T

    private let userDefaults: UserDefaults

    init(key: String, default: T, store: UserDefaults = .standard) {
        self.key = key
        self.defaultValue = `default`
        self.userDefaults = store
    }

    var wrappedValue: T {
        get {
            guard let data = userDefaults.data(forKey: key) else {
                return defaultValue
            }
            let value = try? JSONDecoder().decode(T.self, from: data)
            return value ?? defaultValue
        }
        set {
            let data = try? JSONEncoder().encode(newValue)
            userDefaults.set(data, forKey: key)
        }
    }
}

This wrapper can store/restore any kind of codable into/from the user defaults.这个包装器可以将任何类型的可编码存储到/从用户默认值中恢复。

Usage用法

@UserDefaultStorage(key: "myCustomKey", default: 0)
var myValue: Int

iOS 14 iOS 14

SwiftUI has a similar wrapper (only for iOS 14) called @AppStorage and it can be used as a state. The advantage of using this is that it can be used directly as a State . SwiftUI 有一个类似的包装器(仅适用于 iOS 14),称为@AppStorage ,它可以用作 state。使用它的好处是可以直接用作State But it requires SwiftUI and it only works from the iOS 14.但它需要SwiftUI并且它只适用于 iOS 14。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM