swift属性包装器 propertyWrapper
什么是属性包装器「propertyWrapper」?
在类、结构体或者枚举的声明时使用该特性,可以让其成为一个属性包装器。如果将该特性应用在一个类型上,将会创建一个与该类型同名的自定义特性。将这个新的特性用于类、结构体、枚举的属性,则可以通过包装器的实例封装对该属性的访问。局部和全局变量不能使用属性包装器。
包装器必须定义一个 wrappedValue 实例属性。该属性 wrapped value 是该属性存取方法暴露的值。大多数时候,wrappedValue 是一个计算属性,但它可以是一个存储属性。包装器负责定义和管理其包装值所需的任何底层存储。编译器通过在包装属性的名称前加下划线(_)来为包装器的实例提供同步存储。例如,someProperty 的包装器存储为 _someProperty。包装器的同步存储具有 private 的访问控制级别。
拥有属性包装器的属性可以包含 willSet 和 didSet 闭包,但是不能重写编译器合成的 get 和 set 闭包。
Swift 为属性包装器的构造函数提供了两种形式的语法糖。可以在包装值的定义中使用赋值语法,将赋值语句右侧的表达式作为值传递给属性包装器构造函数中的 wrappedValue 参数。同样的,你也可以为包装器提供一些参数,这些参数将会传递给包装器的构造函数。就像下面的例子,SomeStruct 中,定义 SomeWrapper 的地方各自调用了对应的构造函数。
我们先定义一个Limit的属性包装器,用来限制dog的height和weight
@propertyWrapper
struct Limit{
private var number: Int
private var maximum: Int
private var minimum: Int
var projectedValue: String{
return String(describing: "The value: \(self.number)")
}
var wrappedValue: Int{
get { return number }
set {
if (minimum...maximum).contains(newValue){
number = newValue
}else{
number = minimum
print("设置的值不合理,系统已经为您更改为默认的最小值")
}
}
}
init() {
minimum = 0
maximum = 0
number = 0
}
init(minimum: Int, maximum: Int) {
self.maximum = maximum
self.minimum = minimum
self.number = minimum
}
init(minimum: Int, maximum: Int, number: Int) {
self.maximum = maximum
self.minimum = minimum
self.number = number
self.wrappedValue = self.number
}
}
然后去使用这个包装器
struct DogSize{
@Limit(minimum: 10, maximum: 50) var height: Int
@Limit(minimum: 0, maximum: 50) var weight: Int
}
struct Dog{
var size: DogSize
var name: String
}
let dogSize = DogSize()
var dog = Dog(size: dogSize, name: "tom")
dog.size.height = 500
print(dog.size.$height)
print(dog.size.height)
// 设置的值不合理,系统已经为您更改为默认的最小值
// The value: 10
// 10