属性分为计算属性、存储属性、类型属性
另外,还可以定义属性监视器来监控属性值的变化。属性监视器可以添加到自己写的存储属性上,也可以添加到从父类继承的属性上。
简单来说,一个存储属性就是存储在特定类或结构体的实例里的一个常量或变量。
下面的例子定义了一个名为FixedLengthRange的结构体,他描述了一个在创建后无法修改值域宽度的区间:
struct FixedLengthRange { var firstValue: Int let length: Int } var range = FixedLengthRange(firstValue: 0, length: 3) // 该区间表示整数0,1,2 range.firstValue = 6 // 该区间现在表示整数6,7,8 ,因为length是常量属性,所以之后无法修改它的值。
// 如果创建了一个结构体的实例并赋值给一个常量,则无法修改实例的任何属性,即使定义了变量存储属性: let range = FixedLengthRange(firstValue: 0, length: 4) // 该区间表示整数0,1,2,3 range.firstValue = 6 // 尽管firstValue是个变量属性,这里还是会报错
这种行为是由于结构体(struct)属于值类型。当值类型的实例被声明为常量的时候,它的所有属性也就成了常量。
属于引用类型的类(class)则不一样,把一个引用类型的实例赋给一个常量后,仍然可以修改实例的变量属性。
注意:必须将延迟存储属性声明成变量(使用var关键字),因为属性的值在实例构造完成之前可能无法得到。
class DataImporter { /* DataImporter 是一个将外部文件中的数据导入的类。 这个类的初始化会消耗不少时间。 */ var fileName = "data.txt" // 这是提供数据导入功能 } class DataManager { lazy var importer = DataImporter() var data = [String]() // 这是提供数据管理功能 } let manager = DataManager() manager.data.append("Some data") manager.data.append("Some more data") // DataImporter 实例的 importer 属性还没有被创建
只有使用了lazy,importer属性只有在第一次被访问的时候才被创建。比如访问它的属性fileName时:
println(manager.importer.fileName) // DataImporter 实例的 importer 属性现在被创建了 // 输出 "data.txt”
除存储属性外,类、结构体和枚举可以定义计算属性,计算属性不直接存储值,而是提供一个 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) }
} }
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 没有 setter 的计算属性就是只读计算属性。
注意:必须使用var关键字定义计算属性,包括只读计算属性,因为他们的值不是固定的。let关键字只用来声明常量属性,表示初始化后再也无法修改的值。
只读计算属性的声明可以去掉get关键字和花括号:
struct Cuboid { var width = 0.0, height = 0.0, depth = 0.0 var volume: Double { return width * height * depth } } let four = Cuboid(width: 4.0, height: 5.0, depth: 2.0) println("\(four.volume)") // 输出 "40.0"
那有没有只写属性呢?
属性观察器分为两种:
newValue
oldValue
。注意:willSet
和didSet
观察器在属性初始化过程中不会被调用,它们只会当属性的值在初始化之外的地方被设置时被调用
class StepCounter { var totalSteps: Int = 0 { willSet { println("About to set totalSteps to \(newValue)") } didSet { if totalSteps > oldValue { println("Added \(totalSteps - oldValue) steps") } } } }
注意:
全局的常量或变量都是延迟计算的,跟延迟存储属性相似,不同的地方在于,全局的常量或变量不需要标记lazy
特性。
局部范围的常量或变量不会延迟计算
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 } }
注意:例子中的计算型类型属性是只读的,但也可以定义可读可写的计算型类型属性
获取和设置类型属性的值,通过类名直接访问:
println(SomeClass.computedTypeProperty) // 输出 "42" println(SomeStructure.storedTypeProperty) // 输出 "Some value." SomeStructure.storedTypeProperty = "Another value." println(SomeStructure.storedTypeProperty) // 输出 "Another value.”
结构体中的类型属性:
struct AudioChannel { static let thresholdLevel = 10 static var maxInputLevelForAllChannels = 0 var currentLevel: Int = 0 { didSet { if currentLevel > AudioChannel.thresholdLevel { // 将新电平值设置为阀值 currentLevel = AudioChannel.thresholdLevel } if currentLevel > AudioChannel.maxInputLevelForAllChannels { // 存储当前电平值作为新的最大输入电平 AudioChannel.maxInputLevelForAllChannels = currentLevel } // 这段代码的作用是控制currentLevel的值不超过10 } } }
var leftChannel = AudioChannel() var rightChannel = AudioChannel() leftChannel.currentLevel = 7 print(leftChannel.currentLevel) // prints "7" print(AudioChannel.maxInputLevelForAllChannels) // prints "7" rightChannel.currentLevel = 11 print(rightChannel.currentLevel) // prints "10" print(AudioChannel.maxInputLevelForAllChannels) // prints "10"
let 常量 var 变量 存储属性 var/let 属性监视器 计算属性 var 类型属性 引用类型:如class 计算属性 值类型:如struct、enum 计算属性/存储属性
2015-03-21
19:44:13