@propertyWrapper
是我们比较少用到的技术点,但项目中有用到,所以还是得学习下,偷懒总是不对的。
一、问题引入
如果我们需要在UserDefaults
中存一个是否首次启动的值,需要这样写:
enum Keys {
static let isFirstLaunch = "isFirstLaunch"
}
extension UserDefaults {
var isFirstLaunch: Bool {
get {
return bool(forKey: Keys.isFirstLaunch)
}
set {
set(newValue, forKey: Keys.isFirstLaunch)
}
}
}
如果这样属性有很多,就需要写大量的get 、set
方法,那么有没有办法能不能简化这一系列很类似的写法呢?
答案是有的,就是@propertyWrapper
.
二、@propertyWrapper的使用
@propertyWrapper
的意思就是属性包装,它可以将一系列相似的属性方法进行统一处理。比如上述的例子,我们使用@propertyWrapper
可以这样写:
// 1. 先定义一个属性包装器
@propertyWrapper
struct UserDefaultWrapper<T> {
private let key: String
private let defaultValue: T
init(key: String, defaultValue: T) {
self.key = key
self.defaultValue = defaultValue
}
var wrappedValue: T {
get {
UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
}
set {
UserDefaults.standard.set(newValue, forKey: key)
}
}
}
// 2. 再定义需要的包装的属性
extension UserDefaults {
@UserDefaultWrapper(key: Keys.isFirstLaunch, defaultValue: false)
static var isFirstLaunch: Bool
}
// 3. 使用的地方就变得很简单了
UserDefaults.isFirstLaunch = true // 存值
print(UserDefaults.isFirstLaunch) // 取值
三、进一步了解@propertyWrapper
属性包装器既可以作用于计算属性
又可以作用于静态计算属性
。
@propertyWrapper
struct Wrapper<T> {
var wrappedValue: T
var projectedValue: Wrapper<T> { return self }
func foo() { print("Foo") }
}
struct HasWrapper {
@Wrapper var x = 0
func foo() {
print(x) // 0
print(_x) // Wrapper<Int>(wrappedValue: 0)
print($x) // Wrapper<Int>(wrappedValue: 0)
}
@Wrapper static var y = 0
static func foo2() {
print(y) // 0
print(_y) // Wrapper<Int>(wrappedValue: 0)
print($y) // Wrapper<Int>(wrappedValue: 0)
}
}
// 测试代码
HasWrapper.foo2()
HasWrapper().foo()
更深入了解可参考:Swift Property Wrappers
网友评论