Swift 里我用这个姿势写 UserDefaults
JerrellDoll
8年前
<p>人在江湖飘,总免不了要存一些值到UserDefaults。</p> <pre> <code class="language-swift">UserDefaults.standard.set("@没故事的卓同学", forKey: "Author") let author = UserDefaults.standard.value(forKey: "Author")</code></pre> <p>有存就有取,还可能有很多地方会取这个值。这样的话每次写这个 key 就有点蛋疼了。</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/94d4d3163f98ed52dd142ad471df2034.gif"></p> <p>key 写成一个全局的常量虽然解决了代码重复的问题,但是体验上还是没有改变。一个 app 里也有不少的字符串常量,怎么表明这个字符串是用于持久化的 key 呢?</p> <h2>解决方案</h2> <p>利用 rawValue 类型为 String 的枚举作为 key,通过协议为指定枚举增加存取到 UserDefaults 的能力。</p> <p>首先声明一个枚举,建议在UserDefaults的扩展里写,当然如果你想要省掉前面一个命名空间也是可以的:</p> <pre> <code class="language-swift">extension UserDefaults { enum TestData: String,UserDefaultSettable { case name } }</code></pre> <p>注意到这个枚举需要实现 UserDefaultSettable 协议。</p> <p>接着就可以在这个枚举里调用 store(value: ) 方法来存储:</p> <pre> <code class="language-swift">UserDefaults.TestData.name.store(value: "name") let storeValue = UserDefaults.TestData.name.storedString</code></pre> <p>这个枚举 TestData.name 可以理解为一张银行卡。拿着这张卡到银行,说我要存,就够了。这个枚举就是一个ID。</p> <p>这个思路和Swift 3以后的通知中心形式相似。</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/db5dfd6f7cf76faf8e4ddfa1e65a025c.png"></p> <p>Notification.Name 也是一个 rawValue 为字符串的枚举。</p> <pre> <code class="language-swift">extension NSNotification { public struct Name : RawRepresentable, Equatable, Hashable, Comparable { public init(_ rawValue: String) public init(rawValue: String) } }</code></pre> <p>当然严格的说并不是一个枚举,只是和枚举一样实现了 RawRepresentable 协议。不过我觉得直接声明一个枚举在这里会比实现 RawRepresentable 便捷一些。</p> <h2>实现</h2> <p>主要就是 UserDefaultSettable 协议的扩展了。</p> <pre> <code class="language-swift">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 { // ...... } // 还有支持其他存储类型的函数,就不全写了 }</code></pre> <p>主要的实现代码很简单,就是为 RawValue 为 String 的枚举添加了 store 和 获取存储 value 的方法。</p> <p>为了避免直接取枚举的名字作为key可能引起的重名,声明了一个计算属性来生成存储的 key,规则就是加上枚举 Type 名作为前缀。比如上面的例子里存储的 key 就是 TestData.name 。</p> <p>欢迎关注我的微博:@没故事的卓同学</p> <p>参考链接:</p> <p><a href="/misc/goto?guid=4959738597217756938" rel="nofollow,noindex">Swift: UserDefaults Protocol</a></p> <p><a href="/misc/goto?guid=4959738597316245501" rel="nofollow,noindex">UserDefault 数据存储和读取简易封装</a></p> <p> </p> <p>来自:http://www.jianshu.com/p/332ea092188e</p> <p> </p>