UserDefault 数据存储和读取简易封装

方式一

代码如下:

protocol UserDefaultNameSpace { }

extension UserDefaultNameSpace {
    static func namespace<T>(_ key:T) -> String where T :RawRepresentable {
        return "\(Self.self).\(key.rawValue) "
    }
}

protocol UserDefaultSettable : UserDefaultNameSpace {
    associatedtype UserDefaultKey : RawRepresentable
}

extension UserDefaultSettable where UserDefaultKey.RawValue == String {}

extension UserDefaultSettable {
    
    /// 关于 Int 类型存储和读取
    static func set(value:Int, forKey key:UserDefaultKey){
        let key = namespace(key)
        UserDefaults.standard.set(value, forKey: key)
    }
    
    static func integer(forKey key:UserDefaultKey) -> Int {
        let key = namespace(key)
        return UserDefaults.standard.integer(forKey: key)
    }
    
    /// 关于 String 类型存储和读取
    static func set(value:Any?, forKey key:UserDefaultKey){
        let key = namespace(key)
        UserDefaults.standard.set(value, forKey: key)
    }
    
    static func string(forKey key:UserDefaultKey) -> String? {
        let key = namespace(key)
        return UserDefaults.standard.string(forKey: key)
    }
}

extension UserDefaults {
    
    /*! 关于账号的信息 Key 都放在这里 */
    struct Account: UserDefaultSettable {
        enum UserDefaultKey : String {
            case name
            case age
            case birth
        }
    }
    
    /*! 关于登陆情况 Key 都放在这里 */
    struct LoginStatus: UserDefaultSettable {
        enum UserDefaultKey:String {
            case lastLoginTime
            case sessionTime
        }
    }
}

/// 使用方式
UserDefaults.Account.set(value: 20, forKey: .age)
UserDefaults.Account.set(value: "pmst", forKey: .name)
UserDefaults.Account.set(value: "20170214", forKey: .birth)

方式二

卓同学的另一种实现思路:

public protocol UserDefaultSettable {
    var uniqueKey: String { get }
}

public extension UserDefaultSettable where Self: RawRepresentable, Self.RawValue == String {
    
    public func set(value: Any?){
        UserDefaults.standard.set(value, forKey: uniqueKey)
    }
    
    public var value: Any? {
        return UserDefaults.standard.value(forKey: uniqueKey)
    }
    
    public var stringValue: String? {
        return value as? String
    }
    
    public func set(url: URL?) {
        UserDefaults.standard.set(url, forKey: uniqueKey)
    }
    
    public var urlValue: URL? {
        return UserDefaults.standard.url(forKey: uniqueKey)
    }
    
    public var uniqueKey: String {
        return "\(Self.self).\(rawValue)"
    }
    
    /// removed object from standard userdefaults
    public func removed() {
        UserDefaults.standard.removeObject(forKey: uniqueKey)
    }
    
}

extension UserDefaults {
    enum TestData: String,UserDefaultSettable {
        case name
        case url
    }
}

let value = "testValue"
if let _ = UserDefaults.TestData.name.stringValue {
    assertionFailure("should be nil")
}
UserDefaults.TestData.name.set(value: value)

UserDefaults.TestData.name.stringValue

当然这里我们还商讨了下命名规则,觉得setstringValue不是很恰到,之后会改成 store 动词。

方式三:

智多芯的博客中又提到了一种方式,我觉得也比较好,贴下代码:

final class PreferenceKey<T>: PreferenceKeys { }
class PreferenceKeys: RawRepresentable, Hashable {
    let rawValue: String
    
    required init!(rawValue: String) {
        self.rawValue = rawValue
    }
    
    convenience init(_ key: String) {
        self.init(rawValue: key)
    }
    
    var hashValue: Int {
        return rawValue.hashValue
    }
}
extension PreferenceKeys {
    static let launchAtLogin = PreferenceKey<Bool>("LaunchAtLogin")
    static let launchCount = PreferenceKey<Int>("LaunchCount")
    static let userInfo = PreferenceKey<UserInfo>("UserInfo")
}

接着定义一个专门负责存储的管理类

final class PreferenceManager {
    static let shared = PreferenceManager()
    let defaults = UserDefaults.standard
    
    private init() {
        registerDefaultPreferences()
    }
    
    private func registerDefaultPreferences() {
        // Convert dictionary of type [PreferenceKey: Any] to [String: Any].
        let defaultValues: [String: Any] = defaultPreferences.reduce([:]) {
            var dictionary = $0
            dictionary[$1.key.rawValue] = $1.value
            return dictionary
        }
        defaults.register(defaults: defaultValues)
    }
}
let defaultPreferences: [PreferenceKeys: Any] = [
    .launchAtLogin: false,
    .launchCount: 0,
    .userInfo: NSKeyedArchiver.archivedData(withRootObject: UserInfo(id: 0, name: "")),
]

extension 补充下:

extension PreferenceManager {
    subscript(key: PreferenceKey<Any>) -> Any? {
        get { return defaults.object(forKey: key.rawValue) }
        set { defaults.set(newValue, forKey: key.rawValue) }
    }
    
    subscript(key: PreferenceKey<URL>) -> URL? {
        get { return defaults.url(forKey: key.rawValue) }
        set { defaults.set(newValue, forKey: key.rawValue) }
    }
    
    subscript(key: PreferenceKey<[Any]>) -> [Any]? {
        get { return defaults.array(forKey: key.rawValue) }
        set { defaults.set(newValue, forKey: key.rawValue) }
    }
    
    subscript(key: PreferenceKey<[String: Any]>) -> [String: Any]? {
        get { return defaults.dictionary(forKey: key.rawValue) }
        set { defaults.set(newValue, forKey: key.rawValue) }
    }
    
    subscript(key: PreferenceKey<String>) -> String? {
        get { return defaults.string(forKey: key.rawValue) }
        set { defaults.set(newValue, forKey: key.rawValue) }
    }
    
    subscript(key: PreferenceKey<[String]>) -> [String]? {
        get { return defaults.stringArray(forKey: key.rawValue) }
        set { defaults.set(newValue, forKey: key.rawValue) }
    }
    
    subscript(key: PreferenceKey<Data>) -> Data? {
        get { return defaults.data(forKey: key.rawValue) }
        set { defaults.set(newValue, forKey: key.rawValue) }
    }
    
    subscript(key: PreferenceKey<Bool>) -> Bool {
        get { return defaults.bool(forKey: key.rawValue) }
        set { defaults.set(newValue, forKey: key.rawValue) }
    }
    
    subscript(key: PreferenceKey<Int>) -> Int {
        get { return defaults.integer(forKey: key.rawValue) }
        set { defaults.set(newValue, forKey: key.rawValue) }
    }
    
    subscript(key: PreferenceKey<Float>) -> Float {
        get { return defaults.float(forKey: key.rawValue) }
        set { defaults.set(newValue, forKey: key.rawValue) }
    }
    
    subscript(key: PreferenceKey<Double>) -> Double {
        get { return defaults.double(forKey: key.rawValue) }
        set { defaults.set(newValue, forKey: key.rawValue) }
    }
    
    subscript(key: PreferenceKey<UserInfo>) -> UserInfo? {
        get {
            var object: UserInfo?
            if let data = defaults.data(forKey: key.rawValue) {
                object = NSKeyedUnarchiver.unarchiveObject(with: data) as? UserInfo
            }
            return object
        }
        set {
            if let object = newValue {
                let data = NSKeyedArchiver.archivedData(withRootObject: object)
                defaults.set(data, forKey: key.rawValue)
            }
        }
    }
}

使用方式如下:

let Preferences = PreferenceManager.shared
func demo() {
    let userDefaults = UserDefaults.standard
    
    // Test data.
    var launchAtLogin = true
    var launchCount = 10
    var userInfo: UserInfo? = UserInfo(id: 123, name: "Fox")
    
    // Write preference.
    Preferences[.launchAtLogin] = launchAtLogin
    Preferences[.launchCount] = launchCount
    Preferences[.userInfo] = userInfo
    
    // Read preference.
    launchAtLogin = Preferences[.launchAtLogin]
    launchCount = Preferences[.launchCount]
    userInfo = Preferences[.userInfo]
    
    // Check preferences.
    for (key, value) in userDefaults.dictionaryRepresentation() {
        print("\(key): \(value)")
    }
}

新浪微博:Ninth_Day

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • <<美丽的童话>> 今天偶然想起了童话故事,相信每个人的童年都有童话吧。 小时候,童话对于我们来说只不过是图图新意...
    杰西卡马尔福阅读 232评论 0 0
  • 分享一下最近接两个客单。 喜欢我的小画,就请点赞关注或我的微博:悠井夜JYJ
    悠井夜YJY阅读 356评论 0 4
  • 那时候的太阳应该是初升不久,最能让人感受希望。可以随着漂流的心思触摸和言语。那样的阳光最好,还未刺眼,却已经足够澄...
    山鬼sg阅读 197评论 0 0
  • 你有没有过在街上遇到相熟的人? 电光火石之间四目相对,零点几秒的对视,零点几秒的擦身而过。却花了两秒脚步停顿下来,...
    萌叉叉阅读 286评论 0 0