Swift泛型应用, UserDefault

Posted by P36348 on December 13, 2018

开发中经常会用到UserDefault来存储零碎的数据, 用普通的写法比较低效.

1
let uid = UserDefaults.standard.value(forKey: "userdefault.key.uid") as? Int

可以利用Swift的extension来给Int类型添加便捷的函数:

1
2
3
4
5
6
7
extension Int {
    static func valueFromUserDefault(forKey key: String) -> Int? {
        return UserDefaults.standard.value(forKey: key) as? Int
    }
}

let uid = Int.valueFromUserDefault(forKey: "userdefault.key.uid")

而实际上, UserDefault存储的数据类型还有好几种, 而实现代码其实都是大同小异, 要每一个都这样添加函数就太麻烦了. 有一种更高效的方式给各种类型添加这个函数, 而且也方便统一修改. 就是用泛型和Protocol:

1
2
3
4
5
6
7
8
9
10
11
public protocol UserDefaultable {
    associatedtype E
    
    static func objectUserDefaults(forKey key: String) -> E?
}

extension UserDefaultable {
    public static func valueFromUserDefaults(forKey key: String) -> E? {
        return UserDefaults.standard.value(forKey: key) as? E
    }
}

这样只要声明了遵守UserDefaultable的类型都可以使用valueFromUserDefaults静态函数, 很自然, 这个associatedtype E就是绑定这个类型本身.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
extension Bool: UserDefaultable {
    public typealias E = Bool
}

extension Int: UserDefaultable {
    public typealias E = Int
}

extension Int32: UserDefaultable {
    public typealias E = Int32
}

extension Int64: UserDefaultable {
    public typealias E = Int64
}

extension String: UserDefaultable {
    public typealias E = String
}

extension Double: UserDefaultable {
    public typealias E = Double
}

extension Data: UserDefaultable {
    public typealias E = Data
}

extension Array: UserDefaultable {
    public typealias E = Array
}