UserDefaults是 iOS 中非常常用的一种数据持久化方式,在实际开始中我们一般不会直接使用系统提供的 API 去操作UserDefaults,而是会创建一些扩张,利用扩展的方法来使用UserDefaults。利用 Swift 语言的一些特性,我们可以写出非常优化的UserDefaults扩展。

利用 Swift 的泛型以及subscript,可以实现一个不需要关心存储数据类型的UserDefaults扩展,代码如下:

extension UserDefaults {
    struct Key<Value> {
        var name: String
    }

    subscript<T>(key: Key<T>) -> T? {
        get {
            return value(forKey: key.name) as? T
        }
        set {
            setValue(newValue, forKey: key.name)
        }
    }

    subscript<T>(key: Key<T>, default defaultProvider: @autoclosure () -> T) -> T {
        get {
            return value(forKey: key.name) as? T ?? defaultProvider()
        }
        set {
            setValue(newValue, forKey: key.name)
        }
    }
}

然后使用另外一个扩展定义 Key

extension UserDefaults.Key {
    static var bookmarks: UserDefaults.Key<[String]> {
        return .init(name: "bookmarks")
    }

    static var likeCount: UserDefaults.Key<Int> {
        return .init(name: "likeCount")
    }
}

这样,在使用时就不需要关心类型了

UserDefaults.standard[.likeCount] = 12
let bookmarks = UserDefaults.standard[.bookmarks, default: []]

Swift5 中新增了Property Wrappers特性,利用Property Wrappers也可以使得UserDefaults的使用变得非常优雅:

struct UserDefault<T> {
    let key: String
    let defaultValue: T

    init(_ key: String, defaultValue: T) {
        self.key = key
        self.defaultValue = defaultValue
    }

    var wrappedValue: T {
        get {
            return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
        }
        set {
            UserDefaults.standard.set(newValue, forKey: key)
        }
    }
}

定义UserDefaults的 Key

struct UserDefaultsConfig {
    @UserDefault("likeCount", defaultValue: 12)
    static var likeCount: Int
}

在使用时就可以直接赋值

UserDefaultsConfig.likeCount = 13

上面两种方式唯一不同的点是,第一种方式每次都可以指定不同的defaultValue,而第二种方式只能在定义属性时指定一次defaultValue,使用时不能动态修改defaultValue

个人建议两种方式取其一即可,如果不需要动态修改defaultValue,个人建议使用第二种方式,应为更加简洁明了。

参考资料:

Property wrappers to remove boilerplate code in Swift Property Wrappers The power of subscripts in Swift