属性

![]()

![]()

![]()
属性分为用于存储的属性和用于计算的属性, 用于存储的属性仅提支持类和结构体,而用于计算的属性可以支持类,结构体以及枚举。
延迟存储型属性(lazy stored property)
在一个属性定义前面加上 @lazy 之后,这个属性就变成了lazy stored property,而且,这个属性必须是var定义的,也就是说,常量是不可以加 @lazy的,延迟属性并不会立刻初始化,只有在第一次使用它的时候,才会被初始化。
个人观点,这个东西的意义,如果对于一个代码能力很强,逻辑很严谨的程序员来说没啥意义,当然swift的语法,特性,推出的时机,可以看出这是苹果有意为了降低门槛的有战略意义的产品,所以,提供这样一个类型的属性,无可厚非。
用于计算的属性
这种属性本身并不会保存数值,而是提供了一个getter和一个可选的setter方法,来间接的设置其它属性的值。
官方的例子:
在Rect结构体中,有一个center属性,还有一个origin属性和size属性,而center属性是完全可以通过origin和size计算得到的,并不需要存储,反过来,只移动center的话,那么只要根据新的center点和size属性就可以计算出新的origin属性的值。所以,这个center并不需要保存什么值,它就是一个用于计算,而非用于存储的属性。
上面的例子中,我们为set方法,提供了一个参数叫newCenter,而这个参数可以被省略,由swift来自动提供(当然这种省事儿的办法会让代码变得难读, 又是类型推导惹来的“省事儿”的麻烦),自动提供的参数名叫做newValue,上面的set方法可以写为:
set { //参数省掉了,由swift自动提供
origin.x = newValue.x - (size.width / 2) //newValue 就是swift 自动提供的,在代码里找不到定义的
origin.y = newValue.y - (size.height / 2) // newValue的类型是自动推导得出来的....
}
如果,一个用于计算的属性,只提供了一个get方法,而没有提供set方法的话,那么这个方法就变成了只读的(Read-Only Computed Properties), 但我们依然需要把这个属性定义为 var,而不能定义为let,因为它的值并不是像常量那样是个固定值。
只读型的用于计算的属性,我们可以省掉get 这个关键字,把上面的那个center重新写成:
var center: Point { //get关键字去掉了
let centerX = origin.x + (size.width /2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
//好吧,闭包还没研究明白的同学们,到这里就更要晕菜了
属性观察者(Property Observers)
观察者,是在它监控的那个属性被设置的时候触发的,即使这个属性的新值与原值是一样的。
这里提到了重载,如果对于一个不会被重载的方法,是根本不需要observer的,因为我们可以直接在设置属性的函数里去做一系列操作。
swift为我们提供了两个可选的方法定义observer:
1. willSet
在属性被设置新值,但还没有保存的时候,被调用
2. didSet
在属性保存了新值后,立刻被调用
既然是observer,所以这两个方法都应该是回调类型的,所以我们只管设置就好了。
我们可以给willSet提供一个参数,类似上面的center的set那样,也可以不提供,swift自动提供的参数依然叫newValue。
但对于didSet, swift自动提供的参数,则会被叫做oldValue。
注意:这两种方法,在属性第一次初始化的时候,并不会被调用!
来看官方的例子:
看到上面的写法:
var totalSteps: Int = 0 后面有一个{ },里面放着willSet和didSet,这种又是类似闭包的写法。。。
下面做了个实验:
class MyClass {
var num:Int = 0 {
didSet {
num = oldValue //将 num设置为oldValue
}
}
}
var myClass = MyClass()
myClass.num = 8
println(myClass.num) //得到结果是0
虽然前面说了didSet这个方法调用的时候,num其实已经保存了新值8,但是我在这个方法里,又将num赋值为它之前的值,所以,在外面看来它并没有变。
这个方式就很好玩了,我们可以在很多改变某个变量值的地方省掉很多关联代码,也省去了为某个属性专门提供一个函数去操作设置和读取了,当然,在我们省事儿的同时,也给新接收代码的人增加了理解的难度。
全局常量、变量,也都可以设置用于计算的属性:
var G_myNum = 0
var G_myValue:Int {
return myNum
}
println(myValue)
这里的全局变量 G_myValue 是个lazy型的变量,但对于全局常量、变量,我们并不需要在定义前面加个@lazy,swift会自动让它变成lazy的。
类型属性(Type Properties)
类似于C/C++语言的中的静态变量,所有实例共享一分拷贝,而不是每个实例都有一份。
对于类来说,我们只能给它定义用于计算的类型属性,而其它的值类型的,我们既可以定义用于存储的类型属性,也可以定义用于计算的类型属性。
在swift中,类型属性,依然用了static这个关键字, 而类中要用class关键字(官方的例子):
//至此,又要吐槽一发:class关键字竟然又用了一遍。。。 class语义就有两个了。。。
对于类型属性的读取和设置,就不能像实例属性和方法那样用了,而是要直接使用类型名:
println(SomeStructure.storedTypeProperty)
println(SomeEnumeration.storedTypeProperty)
println(SomeClass.computedTypeProperty)
//再吐槽一发,既然类里面只能有用于计算的类型属性。。。我到底用他来返回谁呢(因为没有存储类型属性,我又不可能返回一个实例属性。。。这个方法到底用来干什么的呢)? 难道是让我用来返回一个全局变量的值?