12.2 计算属性

计算属性本身不存储数据,而是从其他存储属性中计算得到数据。与存储属性不同,类、结构体和枚举都可以定义计算属性。

12.2.1 计算属性概念

计算属性提供了一个getter(取值访问器)来获取值,以及一个可选的setter(设置访问器)来间接设置其他属性或变量的值。计算属性的语法格式如下:

  1. 面向对象类型 类型名 {
  2. 存储属性
  3. ......
  4. var 计算属性名 : 属性数据类型 {
  5. get {
  6. return 计算后属性值
  7. }
  8. set (新属性值) {
  9. ......
  10. }
  11. }
  12. }

计算属性的语法格式比较混乱,这里我们解释一下。第①行的“面向对象类型”包括类、结构体和枚举3种。第②行的“存储属性”表示有很多存储属性。

事实上,第③~⑨行代码才是定义计算属性,变量必须采用var声明。第④~⑥行代码是getter访问器,它其实是一个方法,在访问器中对属性进行计算。最后在第⑤行代码必须使用return语句将计算结果返回。

第⑦~⑧行代码是setter访问器,其中第⑦行代码中,“新属性值”是要赋值给属性值。

定义计算属性比较麻烦,要注意后面的几个大括号的对齐关系。

我们先看一个示例:

  1. import UIKit
  2. class Employee {
  3. var no : Int = 0
  4. var firstName : String = "Tony"
  5. var lastName : String = "Guan"
  6. var job : String?
  7. var salary : Double = 0
  8. lazy var dept : Department = Department()
  9. var fullName : String {
  10. get {
  11. return firstName + "." + lastName
  12. }
  13. set (newFullName) {
  14. var name = newFullName.componentsSeparatedByString(".")
  15. firstName = name[0]
  16. lastName = name[1]
  17. }
  18. }
  19. }
  20. struct Department {
  21. let no : Int = 0
  22. var name : String = ""
  23. }
  24. var emp = Employee()
  25. println(emp.fullName)
  26. emp.fullName = "Tom.Guan"
  27. println(emp.fullName)

上述代码第①行是引入UIKit框架,第②行代码是定义员工的firstName存储属性,第③行代码是定义员工的lastName存储属性。为了获得fullName(全名),fullName = firstName . lastName,不需要定义一个fullName存储属性,而是可以通过firstNamelastName拼接(计算)而成。

第④行代码直接定义fullName计算属性。第⑤行是返回拼接的结果。第⑥行代码中的newFullName是要存储传递进来的参数值,set (newFullName)可以省略如下形式,使用Swift默认名称newValue替换newFullName

  1. set {
  2. var name = newValue.componentsSeparatedByString(".")
  3. firstName = name[0]
  4. lastName = name[1]
  5. }

代码第⑦行是使用String的字符串分割方法componentsSeparatedByString,指定逗号为字符串的分割符号,分割方法返回的是String数组。

第⑧行代码println(emp.fullName)是调用属性的getter访问器,取出属性值。第⑨行代码emp.fullName = "Tom.Guan"是调用属性的setter访问器,给属性赋值。

12.2.2 只读计算属性

计算属性可以只有getter访问器,没有setter访问器,这就是只读计算属性。指定计算属性不仅不用写setter访问器,而且get{}代码也可以省略。与上一节相比,代码将大大减少。修改上一节示例为只读计算属性,代码如下:

  1. class Employee {
  2. var no : Int = 0
  3. var firstName : String = "Tony"
  4. var lastName : String = "Guan"
  5. var job : String?
  6. var salary : Double = 0
  7. lazy var dept : Department = Department()
  8. var fullName : String {
  9. return firstName + "." + lastName
  10. }
  11. }
  12. struct Department {
  13. let no : Int = 0
  14. var name : String = ""
  15. }
  16. var emp = Employee()
  17. println(emp.fullName)

只读计算属性经过简化后,第①行代码是更加简洁的setter访问器。只读计算属性不能够赋值,下列语句是错误的。

  1. emp.fullName = "Tom.Guan"

12.2.3 结构体和枚举中的计算属性

前面介绍的示例都是类的计算属性,本节将介绍一些结构体和枚举中的计算属性,从而比较它们的差异。

示例代码如下:

  1. struct Department {
  2. let no : Int = 0
  3. var name : String = "SALES"
  4. var fullName : String {
  5. return "Swift." + name + ".D"
  6. }
  7. }
  8. var dept = Department()
  9. println(dept.fullName)
  10. enum WeekDays : String {
  11. case Monday = "Mon."
  12. case Tuesday = "Tue."
  13. case Wednesday = "Wed."
  14. case Thursday = "Thu."
  15. case Friday = "Fri."
  16. var message : String {
  17. return "Today is " + self.toRaw()
  18. }
  19. }
  20. var day = WeekDays.Monday
  21. println(day.message)

上述代码第①行定义了结构体Department,第②行定义了只读属性fullName,第③行是读取fullName属性。

第④行定义了枚举类型WeekDays,第⑤行定义了只读属性message,第⑥行代码中使用了self.toRaw()语句将当前实例值转换为原始值,其中self代表当前实例,toRaw()方法是转换为原始值,否则不能进行字符串拼接。代码第⑦行是读取message属性。