一、包装属性
属性包装(propertyWrapper)写法:
- 建立一个类型,并标识
@propertyWrapper
。 - 必须有一个名为
wrappedValue
,并且至少可以get
的属性。 wrappedValue
可以是普通属性,也可以是计算属性。- 可以加上
projectedValue
投射任何属性或是本身。 - 不止用在
struct
,也可以用在class
、enum
。
使用限制:
- 不能用于计算属性。
- 不能用于全局属性。
- 不能用于
lazy
、weak
或unowned
。 PropertyWrapper
、wrappedValue
、projectedValue
必须有相同的访问控制级别。
@propertyWrapper
struct ChangeLog<T> {
// 必须有 wrappedValue
var wrappedValue: T {
didSet {
print("\(desc)的值被改变为 \(wrappedValue)")
}
}
// 投射属性,类型任意,最常用是投射本身
// 使用投射后,外部可以通过 $ 的方式读取 private 属性的方法或变量。
var projectedValue: Self { self }
private(set) var desc: String
}
struct Bill {
@ChangeLog(desc: "用途") var purpose: String = ""
@ChangeLog(desc: "花费") var cost: Int = 0
private var test: String = ""
init(purpose: String, cost: Int) {
self.purpose = purpose
self.cost = cost
}
}
var spend = Bill(purpose: "蜜雪冰城", cost: 15)
print(spend.purpose, spend.cost) // print: 蜜雪冰城 15
spend.cost = 35 // print: 花费的值被改变为 35
spend.purpose = "蜜雪冰城 + 华莱士" // print: 用途的值被改变为 蜜雪冰城 + 华莱士
// desc 是一个 private 变量,因为上面使用了投射属性 projectedValue,
// 所以这里可以直接通过 $ + 变量名的方式访问 ChangeLog 中的 private 变量。
print(spend.$purpose.desc) // print: 用途