67. 如果结构体(Struct)的实例被声明为常量的话,就不能对其属性进行修改,即使是var类型的属性。而对于类(Class)来说则不是这样,如果一个类的实例被声明为常量,仍然可以修改其var属性。
68. 惰性属性(lazy property),使用关键字@lazy(添加在声明前面),惰性属性在使用时才会进行初始化,在声明时一定要将惰性属性声明为var类型,因为常量属性在初始化函数执行前之前必须要进行初始化赋值。惰性属性可以用于那种需要等所有的初始化工作都执行完了才能进行初始化的属性,也可以针对那些需要复杂的初始化过程,或者初始化过程非常耗时的属性来设置,例如:
class VeryLargeAndComplexClass {
…
}
class DemoClass {
@lazy var cls = new VeryLargeAndComplexClass()
}
69. 在Swift中,没有属性(property)和字段(field)之分,所有的成员都统一为属性,用来存储属性的内容的变量不可访问,只能通过属性来对其操作。
70. 同样,Swift中可以为属性定义访问器getter和setter,例如:
var description : String {
get {
return “name : \(name), age : \(age)”
}
set (newDescription) {
if newDescription != nil {
description =newDescription
}
}
}
上面的set方法如果省略掉(newDescription)的定义,默认Swift会生成一个newValue作为要赋的值的名字,所以,上面的set方法也可以简写为:
set {
if newValue != nil {
description =newValue
}
}
如果只定义get,不定义set方法,则属性为只读的。只读属性可以省略get关键字,例如:
var description : String {
return “name : \(name), age : \(age)”
}
71. 属性观察器用来对属性的赋值操作进行处理,除了惰性属性之外,你可以为任何属性添加观察器。可以为属性添加willSet和didSet两个观察器,willSet在属性赋值前被触发,didSet在属性赋值后被触发,在属性第一次赋值,即初始化的时候,willSet和didSet不会触发。willSet和didSet方法与set方法一样,允许用圆括号定义一个值的名称,当省略圆括号和自定义的名称时,对于willSet方法,会使用newValue作为默认名称,对于didSet,会使用oldValue作为默认名称。下面是个具体的例子:
class Demo {
var description :String = "test" {
willSet {
println(newValue)
}
didSet {
println(oldValue)
}
}
}
如果定义了willSet和didSet方法,就不必写get和set方法了,否则会有编译错误。
72. 除了属性,全局变量和局部变量也可以定义get、set、willSet和didSet方法。
73. Swift中的静态变量(或者说类型变量)的定义对于类(Class)、枚举类型和结构体是有区别的(前者是引用类型,后两种是值类型)。对于类来说,定义的时候使用class关键字来修饰,对于枚举类型和结构体,定义的时候使用static关键字。此外,对于枚举类型和结构体,在定义静态变量上没有限制,而类中的静态变量必须为计算类型变量(具有get、set等方法的变量)。例如:
struct DemoStruct {
static var storedProp = “test”
static var computedProp : Int {
return 1
}
}
enum DemoEnum {
static var storedProp = “test”
static var computedProp : Int {
return 1
}
}
class DemoClass {
class var computedProp : Int {
return 1
}
}
74. Swift中的方法(类、结构体、枚举中定义的函数)和函数在语法上没有区别,但是对于带参数的方法来说,第一个参数的定义是正常的,第二个参数以及后面的其他参数,他们的外部名称和内部名称相同,默认Swift就已经定义好了,也就是相当于Swift替我们在除了第一个参数以外的其他参数定义上都加上了“#”符号。这种用法是按照Object-C的编写习惯来设计的。例如:
class DemoClass {
func demoFunc(p1 :Int, p2 : String) {
println("\(p2) \(p1)")
}
}
var cls = DemoClass()
cls.demoFunc(1, p2: "abc")
如果我们不希望Swift这种默认的处理方式,想要不使用外部名称来调用的话,只需要在想要处理的参数的外部名称的位置显式地使用下划线“_”来代替外部名称即可:
class DemoClass {
func demoFunc(p1 :Int, _ p2 : String) {
println("\(p2) \(p1)")
}
}
var cls = DemoClass()
cls.demoFunc(1, "abc")
75. 结构体、枚举类型为值类型,因此在其中定义的方法不能够修改结构体和枚举类型的自身属性,如果确实想要这么做,可以在方法定义前面添加mutating关键字来修饰。但是如果结构体或者枚举类型的实例被定义为常量的话,添加mutating关键字也不能修改其属性。此外,在mutating关键字修饰的方法中,还可以为self赋值。
76. mutating关键字、方法、self在枚举类型中的应用:
enum Level {
case Level1,Level2, Level3
mutating functurnToNextLevel() {
switch self {
case Level1:
self =Level2
case Level2:
self =Level3
case Level3:
self =Level1
}
}
}
var lvl = Level.Level1
lvl.turnToNextLevel() //lvl现在变成Level2了
77. Swift中的静态方法(或者说类型方法)和静态属性的定义类似,对于类中的静态方法,在func关键字前面加上class关键字,对于枚举类型或者结构体等值类型,在func关键字前面加上static关键字修饰。与其他语言不通,Swift在静态方法中仍然可以使用self关键字,只不过此时self关键字指的是类本身而不是某个实例,因此可以通过self关键字来引用静态属性。
78. 在Swift中可以为类、结构体和枚举类型定义下标(subscript),下标的用法类似于数组和字典中下标的用法,下标定义使用subscript关键字,例如:
struct TwoDimentionArray {
var width : Int
var height : Int
var array : Int[]
init(height : Int,width : Int) {
self.width =width
self.height =height
self.array =Array(count : width * height, repeatedValue : 0)
}
subscript(i : Int,j : Int) -> Int {
get {
returnarray[(i - 1) * width + j - 1]
}
set (newValue){
array[(i -1) * width + j - 1] = newValue
}
}
func showElements(){
println(array)
}
}
var twoDArray = TwoDimentionArray(height: 3, width: 6)
twoDArray.showElements()
twoDArray[2, 6] = 10
twoDArray.showElements()
上面代码中使用一维数组来模拟一个二维数组。从代码中可以看到,下标中使用get和set来定义读写方法。
如果只定义get方法,则下标的为只读的,此时可以省略get关键字和它的花括号。set方法可以省略newValue参数和它的圆括号,Swift默认会生成一个名叫newValue的默认参数(这部分用法和get、set用法一样)。下标的参数不一定非要是Int类型,可以使任何类型的,也可以使用参数列表,但是不能使用inout参数或者设置参数默认值。
一个类或者结构体可以定义很多个下标定义。
79. Swift中使用init来定义初始化方法。