Swift文档Chapter 10 属性


属性将值与特定的类,结构体或者枚举关联。属性分为:

  • 存储属性,将常量和变量存储成为实例的一部分,可以用于类和结构体;
  • 计算属性,直接计算值,可以用于类,结构体和枚举。

存储属性

存储属性是存储在特定类或者结构体实例里的变量或者常量。变量使用var定义,常量使用let定义。

常量结构体的存储属性

定义为常量的结构体中的存储属性在第一次赋值后不可以修改,即使结构体内部声明成了变量,因为结构体是值类型
类即使声明成常量,内部的变量存储属性依然可以更改,因为类是引用类型

延迟加载存储属性

延迟加载存储属性是只有在第一次调用的时候才会计算初始值的属性。在属性声明前加上lazy表示延时加载存储属性。
延时加载存储属性必须用var,因为常量属性在构造完成之前必须有初始值,不能完成延时加载。
当属性的值依赖于外部因素或者外部因素在构造结束才能知道时,或者属性计算非常的耗时的时候,适合使用延迟加载存储属性。
如果被标记为lazy的属性在没初始化时就被多个线程访问,无法保证这个属性只被初始化一次。

计算属性

计算属性不直接存储值,而是提供一个getter和可选的setter来间接获取或者设置其他属性或变量的值。以矩形的结构体作为例子:

struct Point {
    var x = 0.0, y = 0.0
}
struct Size {
    var width = 0.0, height = 0.0
}
struct Rect {
    var origin = Point()
    var size = Size()
    var center: Point {
        get {
            let centerX = origin.x + (size.width / 2)
            let centerY = origin.y + (size.height / 2)
            return Point(x: centerX, y: centerY)
        }
        set(newCenter) {
            origin.x = newCenter.x - (size.width / 2)
            origin.y = newCenter.y - (size.height / 2)
        }
    }
}

简化setter声明

如果计算属性没有定义新值的参数名,默认使用newValue作为新的参数名,简化后如下:

struct AlternativeRect {
    var origin = Point()
    var size = Size()
    var center: Point {
        get {
            let centerX = origin.x + (size.width / 2)
            let centerY = origin.y + (size.height / 2)
            return Point(x: centerX, y: centerY)
        }
        set {
            origin.x = newValue.x - (size.width / 2)
            origin.y = newValue.y - (size.height / 2)
        }
    }
}

简化getter声明

如果整个getter是一个单一的表达式,会隐式的返回这个结果,省略return

struct CompactRect {
    var origin = Point()
    var size = Size()
    var center: Point {
        get {
            Point(x: origin.x + (size.width / 2),
                  y: origin.y + (size.height / 2))
        }
        set {
            origin.x = newValue.x - (size.width / 2)
            origin.y = newValue.y - (size.height / 2)
        }
    }
}

只读计算属性

只有getter没有setter的属性称为只读计算属性。可以通过点运算符访问,但是不可以赋值。
所有的计算属性都必须声明为var类型,因为他们的值是不固定的。

属性观察器

属性观察器监控和响应属性值变化,每次属性被设置值时都会调用,即使是设置和原来一样的值。可以为延时属性之外的属性添加观察器。

可以为属性添加两个观察器:

  • willSet在新的值被设置之前调用,新的值会作为参数传入,如果不定义参数名称,默认为newValue
  • didSet在新的值被设置之后调用,旧的值会作为参数传入,如果不命名默认为oldValue,如果在didSet方法中再次对该属性赋值,那么新值会覆盖旧的值。

全局变量和局部变量

全局变量是在函数,方法,闭包或任何类型之外定义的变量,局部变量是在函数、方法或闭包内部定义的变量。
全局变量总是延迟计算的,只不过不需要lazy的标注。局部范围的常量和变量从不延迟计算。

类型属性

类型属性不论创建多少份实例,这个属性只有一份。类似于C语言的静态属性。存储型类型属性可以是变量或者常量,计算型类型属性必须是变量。

类型属性定义

使用static关键字定义类型属性。在类中定义计算型类型属性的时候,可以使用class关键字支持子类对父类的重写。

struct SomeStructure {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 1
    }
}
enum SomeEnumeration {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 6
    }
}
class SomeClass {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 27
    }
    class var overrideableComputedTypeProperty: Int {
        return 107
    }
}

类型属性的获取

类型属性的获取也是通过点运算符访问。但是不是通过实例访问,而是直接通过类型访问。