简介:
关于SwiftyUserDefaults的使用详情可看项目的GitHub地址,本文不再阐述,OK,let's begin!
Proxy:
该类是UserDefaults 拓展中的嵌套类。
class Proxy {
fileprivate let defaults: UserDefaults
fileprivate let key: String
fileprivate init(_ defaults: UserDefaults, _ key: String) {
self.defaults = defaults
self.key = key
}
}
该类有两个存储属性和一个初始化方法,都是私有不对外公开的。
除此之外,该类还有一大堆可选和非可选的计算型属性。
public var string: String? {
return defaults.string(forKey: key)
}
public var stringValue: String {
return string ?? ""
}
两者的本质都是用defaults属性根据返回值的类型调用相应的取值方法,区别是非可选的属性名是以类型加value结尾的,并且会在可选计算属性值为nil的时候返回一个默认值。另外一点值得注意的是,该类还number拆分为int,double和bool,非常实用,可能你会觉得奇怪为什么该类的计算属性都是只读的,没关系下面会见到的。
UserDefaults拓展:
同样,在UserDefaults的拓展中,也对NSNumber类型的取值开了额外的方法,不过,这里没有细分为对应的int,double和bool。
func numberForKey(_ key: String) -> NSNumber? {
return object(forKey: key) as? NSNumber
}
下标:
public subscript(key: String) -> Proxy {
return Proxy(self, key)
}
这里上面的Proxy类就被用到了,通过访问UserDefaults实例下标key我们将返回一个Proxy对象,该对象里面存储了UserDefaults实例本身和参数key,将key和UserDefault实例一一绑定。这里主要还是为了获取key,有了key我们可以通过Proxy的实例方法根据不同类型的值获取相应的计算属性的值。可能这里你又有疑惑了,我怎么知道我该调用stringValue还是arrayValue,要记住每次存了什么类型的值得多操心啊,没事别急,后面会讲到。
public subscript(key: String) -> Any? {
get {
// return untyped Proxy
// (make sure we don't fall into infinite loop)
let proxy: Proxy = self[key]
return proxy
}
set {
guard let newValue = newValue else {
removeObject(forKey: key)
return
}
switch newValue {
// @warning This should always be on top of Int because a cast
// from Double to Int will always succeed.
case let v as Double: self.set(v, forKey: key)
case let v as Int: self.set(v, forKey: key)
case let v as Bool: self.set(v, forKey: key)
case let v as URL: self.set(v, forKey: key)
default: self.set(newValue, forKey: key)
}
}
}
接着又对下标进行了重载,将返回类型限定为Proxy,同时在set的时候做了真正的业务操作,将值进行保存。这是一个很巧妙的做法,通过调用UserDefaults实例的下标,我们设置在value的时候完成了真的的存储,而在想要取value值的时候我们可以根据value的类型取Proxy实例相应的计算属性。至此Proxy类的作用已经很明显了,为我们的UserDefaults做代理,根据想要的类型取出相应的值,避免了swift啰嗦的可选与类型转换处理。
判断是否有值:
public func hasKey(_ key: String) -> Bool {
return object(forKey: key) != nil
}
移除值:
public func remove(_ key: String) {
removeObject(forKey: key)
}
public func removeAll() {
for (key, _) in dictionaryRepresentation() {
removeObject(forKey: key)
}
}
全局常量:
public let Defaults = UserDefaults.standard
这里定义了一个全局常量,我们可以在项目中新建一个.swift文件,倒入SwiftyUserDefaults框架,在文件中定义一个同名常量:
let Defaults = SwiftyUserDefaults.Defaults
这样我们就可以尽情使用SwiftyUserDefaults框架了,而不是每次要在使用的文件都倒入一遍SwiftyUserDefaults框架。
DefaultsKeys:
open class DefaultsKeys {
fileprivate init() {}
}
该类的作用差不多就是一个充当一个容器,从命名就可以看出来,通过extension添加静态key的方式集中管理key。
####DefaultsKey:
open class DefaultsKey<ValueType>: DefaultsKeys {
// TODO: Can we use protocols to ensure ValueType is a compatible type?
public let _key: String
public init(_ key: String) {
self._key = key
super.init()
}
}
剧透下,该类该框架的核心类,用来定义各种类型的key和相应的value的,你的疑惑终于要解开了。
该类是一个泛型类,用来定义key与相应的ValueType,这个时候泛型的优势就体现出来了。
我们知道,我们之前都是通过下标进行value的存取的,不过key的类型都是String,这里为了支持该类型的key,我们需要添加相应的方法支持。
自定义类型key的value的设置:
extension UserDefaults {
/// This function allows you to create your own custom Defaults subscript. Example: [Int: String]
public func set<T>(_ key: DefaultsKey<T>, _ value: Any?) {
self[key._key] = value
}
}
本质还是通过下标,用DefaultsKey的key来设置value的。
自定义类型key的value的判断和移除:
public func hasKey<T>(_ key: DefaultsKey<T>) -> Bool {
return object(forKey: key._key) != nil
}
判断是否有值。
public func remove<T>(_ key: DefaultsKey<T>) {
removeObject(forKey: key._key)
}
移除该key。
下标支持自定义类型key:
extension UserDefaults {
public subscript(key: DefaultsKey<String?>) -> String? {
get { return string(forKey: key._key) }
set { set(key, newValue) }
}
public subscript(key: DefaultsKey<String>) -> String {
get { return string(forKey: key._key) ?? "" }
set { set(key, newValue) }
}
}
好吧,上一步的set方法就是为这里的下标赋值做铺垫的。这里的下标取值直接用了UserDefaults实例自己的方法取的。为啥?这部很明显么,都知道ValueType类型了,还用Proxy干啥?
以上都是常见的ValueType,如果想支持别的支持NSCoding的ValueType,重载该方法就可以了,不过需要调用archive和unarchive。
public func unarchive<T>(_ key: DefaultsKey<T>) -> T? {
return data(forKey: key._key).flatMap { NSKeyedUnarchiver.unarchiveObject(with: $0) } as? T
}
public func unarchive<T>(_ key: DefaultsKey<T?>) -> T? {
return data(forKey: key._key).flatMap { NSKeyedUnarchiver.unarchiveObject(with: $0) } as? T
}
实现:
let Defaults = SwiftyUserDefaults.Defaults
// userInfo
extension DefaultsKeys {
static let name = DefaultsKey< String?>("name")
static let age = DefaultsKey<Int?>("age")
static let sex = DefaultsKey< Sex?>("sex")
}
enum Sex {
case man,women
}
extension UserDefaults {
subscript(key: DefaultsKey< Sex?>) -> Sex? {
get { return unarchive(key) }
set { archive(key, newValue) }
}
}
示例:
let user = User(name:"meow",age: 1,sex: .man)
Defaults[. name] = user.name
Defaults[. age] = user.age
Defaults[. sex] = user. age
网友评论