在iOS UserDefaults中存储字典

时间:2018-03-05 02:32:21

标签: swift core-data io nsuserdefaults swift4

目前我:

// Save
defaults.set(Settings.hostname, forKey: "hostname")
defaults.set(Settings.current_user, forKey: "current_user")
defaults.set(Settings.access_token, forKey: "access_token")

// Load
Settings.hostname = defaults.string(forKey: "hostname")
Settings.current_user = defaults.string(forKey: "current_user")
Settings.access_token = defaults.string(forKey: "access_token")

每个人都会didSet调用save

但这似乎是糟糕的设计。所以现在我正在尝试用enumstruct写一个值为类型的数组和一个数组:

enum SettingsKeys: Int {
    case hostname = 0
    case current_user
    case access_token
    static let count: Int = {
        var max: Int = 0
        while let _ = SettingsKeys(rawValue: max) { max += 1 }
        return max
    }()
}

struct TypeValue {
    type: // TODO
}

class Settings: Loopable {
    private static var settings = [Any?](repeating: nil, count: SettingsKeys.count);

    //...

但这看起来很糟糕,可能不是斯威夫特。

我是如何保存/加载在整个应用中使用的设置?

2 个答案:

答案 0 :(得分:1)

我会将SettingsKey设为String枚举,而不是Int,然后编写一个类来使用键加载和保存值。原始价值。

class Settings {
    static let standard = Settings()

    enum SettingsKeys: String {
        case hostname
        case current_user
        case access_token
    }

    private func object<T>(forKey: SettingsKey) -> T? {
        return UserDefaults.standard.object(forKey: key.rawValue) as? T
    }

    private func set<T>(_ value: T, forKey key: SettingsKey) {
        UserDefaults.standard.set(value, forKey: key.rawValue)
    }

    static var hostname: String {
        get { return self.object(forKey: .hostname) }
        set { self.set(newValue, forKey: .hostname) }
    }

    // etc for other values
}

请注意,如果没有正确迁移,您可能无法更改版本之间的枚举键名称。

如果您有许多相同类型的设置(例如String),那么最好将它们组合成下标运算符:

subscript(_ key: StringKeys) -> String {
    get { return self.object(forKey: key) ?? "uh oh" }
    set { self.set(newValue, forKey: key) }
}

答案 1 :(得分:0)

我删除了Core Data代码,因为您的问题没有提及与Core Data相关的任何内容,但仍然没有。

要将某些内容保存到用户默认值,数据结构中的所有内容都必须是属性列表类型。那个数组,字典,字符串,日期,数字,布尔值和二进制数据blob(Swift中的Data)。此外,字典键必须是字符串。您无法直接编写枚举或结构,您需要将它们转换为仅需要属性列表类型的其他形式。

一种方法是将设置放在结构中,然后依靠Codable将结构转换为/ Data ::

struct Settings : Codable {
    var hostname:String
    var current_user:String
    var access_token:String
}

let mySettings = Settings(hostname: "hostfoo", current_user: "userfoo", access_token: "accessfoo")

let encoder = JSONEncoder()
let mySettingsData = try? encoder.encode(mySettings)

UserDefaults.standard.set(mySettingsData, forKey: "data")

使用核心数据是没有意义的,除非你有多个设置集合,一次将它们全部读入内存是很尴尬的。您提到的自动序列化可能是Core Data&#34; transformable&#34;属性类型。如果值符合Data协议,则可以自动将转换转换为NSCoding。但NSCoding需要对象,而不是结构或枚举或其他任何东西,而且只适用于继承自NSObject的类。