美文网首页Swift移动开发技术前沿iOS && Android
Swift里我用这个姿势写UserDefaults

Swift里我用这个姿势写UserDefaults

作者: 没故事的卓同学 | 来源:发表于2017-02-22 14:49 被阅读2686次

    github地址:UserDefaultsEVO

    人在江湖飘,总免不了要存一些值到UserDefaults。

    UserDefaults.standard.set("@没故事的卓同学", forKey: "Author")
    
    let author = UserDefaults.standard.value(forKey: "Author")
    

    有存就有取,还可能有很多地方会取这个值。这样的话每次写这个 key 就有点蛋疼了。


    key 写成一个全局的常量虽然解决了代码重复的问题,但是体验上还是没有改变。一个 app 里也有不少的字符串常量,怎么表明这个字符串是用于持久化的 key 呢?

    解决方案

    利用 rawValue 类型为 String 的枚举作为 key,通过协议为指定枚举增加存取到 UserDefaults 的能力。
    首先声明一个枚举,建议在UserDefaults的扩展里写,当然如果你想要省掉前面一个命名空间也是可以的:

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

    注意到这个枚举需要实现<code>UserDefaultSettable</code>协议。
    接着就可以在这个枚举里调用<code>store(value: )</code>方法来存储:

     UserDefaults.TestData.name.store(value: "name")
     let storeValue = UserDefaults.TestData.name.storedString
    

    这个枚举<code>TestData.name</code>可以理解为一张银行卡。拿着这张卡到银行,说我要存,就够了。这个枚举就是一个ID。

    这个思路和Swift 3以后的通知中心形式相似。



    Notification.Name 也是一个 rawValue 为字符串的枚举。

    extension NSNotification {
        public struct Name : RawRepresentable, Equatable, Hashable, Comparable {
    
            public init(_ rawValue: String)
    
            public init(rawValue: String)
        }
    }
    

    当然严格的说并不是一个枚举,只是和枚举一样实现了<code>RawRepresentable</code>协议。不过我觉得直接声明一个枚举在这里会比实现<code>RawRepresentable</code>便捷一些。

    实现

    主要就是<code>UserDefaultSettable</code>协议的扩展了。

    public protocol UserDefaultSettable {
        var uniqueKey: String { get }
    }
    
    public extension UserDefaultSettable where Self: RawRepresentable, Self.RawValue == String {
    
        public func store(value: Any?){
            UserDefaults.standard.set(value, forKey: uniqueKey)
        }
    
        public var storedValue: Any? {
            return UserDefaults.standard.value(forKey: uniqueKey)
        }
    
        // 为所有的key加上枚举名作为命名空间,避免重复
        public var uniqueKey: String {
            return "\(Self.self).\(rawValue)"
        }
    
        public func store(value: Bool) {
            // ......
        }
        public var storedBool: Bool {
                  // ......
        }
        // 还有支持其他存储类型的函数,就不全写了
    }
    

    主要的实现代码很简单,就是为 RawValue 为 String 的枚举添加了 store 和 获取存储 value 的方法。

    为了避免直接取枚举的名字作为key可能引起的重名,声明了一个计算属性来生成存储的 key,规则就是加上枚举 Type 名作为前缀。比如上面的例子里存储的 key 就是 TestData.name 。

    欢迎关注我的微博:@没故事的卓同学


    参考链接:
    Swift: UserDefaults Protocol
    UserDefault 数据存储和读取简易封装

    相关文章

      网友评论

      本文标题:Swift里我用这个姿势写UserDefaults

      本文链接:https://www.haomeiwen.com/subject/mkipwttx.html