存储属性
存储属性可以存储数据,分为常量属性(用关键字let定义)和变量属性(用关键字var定义)。存储属性适用于类和结构体两种Swift面向对象类型。
存储属性概念
class Employee {
let no : Int = 0
var name : String = ""
var job : String?
var salary : Double = 0
var dept : Department?
}
struct Department {
let no : Int = 0
var name : String = ""
}
var emp = Employee()
emp.no = 100 //编译错误
let dept = Department()
dept.name = 30 //编译错误
let emp1 = Employee()
emp1.name = "Tony"
实例通过点(.)运算符调用属性。代码emp.no = 100修改常量属性,程序发生编译错误,dept.name = 30也会发生编译错误,因为实例dept本身是常量,即便它的属性name是变量属性,也不能修改。但是代码emp1.name = "Tony"可以编译通过,emp1实例也是常量,name是变量属性。因为emp1是类实例,是引用类型,dept是结构体实例,是值类型。引用类型相当于指针,其常量也可以修改,但值类型的常量是不能修改的。
延迟存储属性
print("--延迟存储属性--")
class Employee {
var no : Int = 0
var name : String = ""
var job : String?
var salary : Double = 0
lazy var dept : Department = Department()
}
struct Department {
let no : Int = 0
var name : String = ""
}
let emp = Employee()
在dept属性前面添加了关键字lazy声明,这样dept属性就是延时加载。延时加载,顾名思义,就是dept属性只有在第一次访问它的时候才加载,如果永远不访问,它就不会创建,这样就可以减少内存占用。
属性观察者
为了监听属性的变化,可以使用Swift提供的以下属性观察者。
- willSet在设置新的值之前调用
- didSet在新值被设置之后马上调用
可以根据需要,使用部分或全部的属性观察者。它们不能应用于延迟存储属性,但能够应用于一般的存储属性和计算属性。
计算属性
计算属性本身不存储数据,而是从其他存储属性中计算得到数据。与存储数据不同,类、结构体和枚举都可以定义计算属性。
计算属性概念 计算属性提供了一个getter(取值访问器)来获取值,以及一个可选的setter(设置访问器)来间接设置其他属性或变量的值。计算属性的语法格式如下:
面向对象类型 类型名 {
存储属性
......
var 计算属性名 : 属性数据类型 {
get {
return 计算后属性值
}
set (新属性值) {
......
}
}
}
“面向对象类型”包括类、结构体和枚举3种。"存储属性"表示有很多存储属性。
示例:
import UIKit
class Employee {
var no : Int = 0
var firstName : String = "Tony"
var lastName : String = "Guan"
var job : String?
var salary : Double = 0
lazy var dept : Department = Department()
var fullName : String {
get {
return firstName + "." + lastName
}
// set (newFullName) {
// var name = newFullName.componentsSeparatedByString()
// firstName = name[0]
// lastName = name[1]
// }
set {
var name = newValue.componentsSeparatedByString(".")
firstName = name[0]
lastName = name[1]
}
}
}
struct Department {
let no : Int = 0
var name : String = ""
}
var emp = Employee()
print(emp.fullName)
emp.fullName = "Tom.Guan"
print(emp.fullName)
引入UIKit框架,set (newFullName)可以省略如下形式,使用Swift默认名称newValue替换newFullName。
set {
var name = newValue.componentsSeparatedByString(".")
firstName = name[0]
lastName = name[1]
}
newValue.componentsSeparatedByString(".")使用String的字符串分割方法componentsSeparatedByString,指定点为字符串的分割符号,分割方法返回的是String数组。
只读计算属性
计算属性可以只有getter访问器,没有setter访问器,这就是只读计算属性。指定计算属性不仅不用写setter访问器,而且get{}代码也可以省略。修改示例为只读计算属性,代码如下:
import UIKit
class Employee {
var no : Int = 0
var firstName : String = "Tony"
var lastName : String = "Guan"
var job : String?
var salary : Double = 0
lazy var dept : Department = Department()
var fullName : String {
return firstName + "." + lastName
}
}
struct Department {
let no : Int = 0
var name : String = ""
}
var emp = Employee()
print(emp.fullName)
只读计算属性不能够赋值。
结构体和枚举中的计算属性
示例代码:
import UIKit
struct Department {
let no : Int = 0
var name : String = "SALES"
var fullName : String {
return "Swift." + name + ".D"
}
}
var dept = Department()
print(dept.fullName)
enum WeekDays : String {
case Monday = "Mon."
case Tuesday = "Tue."
case Wednesday = "Wed."
case Thursday = "Thu."
case Friday = "Fri."
var message : String {
return "Today is " + self.rawValue
}
}
var day = WeekDays.Monday
print(day.message)
属性观察者
为了监听属性的变化,Swift提供了属性观察者。属性观察者能够监听存储属性的变化,即便变化前后的值相同,它们也能监听到。但它们不能监听延迟存储属性和常量存储属性的变化。
Swift中的属性观察者主要有以下两个。
- willSet:观察者在修改之前调用
- didSet:观察者在修改之后立刻调用
属性观察者的语法格式如下:
面向对象类型 类型名 {
......
var 存储属性 : 属性数据类型 = 初始化值 {
willSet(新值) {
......
}
didSet(旧值) {
......
}
}
}
属性观察者的语法格式比计算属性还要混乱。“面向对象类型”包括类和结构体,不包括枚举,因为枚举不支持存储属性。
class Employee {
var no : Int = 0
var name : String = "Tony" {
willSet (newNameValue) {
print("员工name新值:\(newNameValue)")
}
didSet (oldNameValue) {
print("员工name旧值:\(oldNameValue)")
}
}
var job : String?
var salary : Double = 0
var dept : Department?
}
struct Department {
var no : Int = 10 {
willSet {
print("员工编号新值:\(newValue)")
}
didSet {
print("员工编号旧值:\(oldValue)")
}
}
var name : String = "RESEARCH"
}
var emp = Employee()
emp.no = 100
emp.name = "Smith"
var dept = Department()
dept.no = 30
静态属性
一个类的设计:有一个Account(银行账户)类,假设它有3个属性:amount(账户金额)、interestRate(利率)和owner(账户名)。在这3个属性中,amount和owner会因人而异,不同的账户这些内容是不同的,而所有账户的interestRate都是相同的。
amount和owner属性与账户个体有关,称为实例属性。interestRate属性与个体无关,或者说是所有账户个体共享的,这种属性称为静态属性或类型属性。
3种面向对象类型(结构体、枚举和类)都可以定义静态属性,它们的语法格式分别如下所示:
struct 结构体名 {
static var(或let) 存储属性 = "xxx"
......
static var 计算属性名 : 属性数据类型 {
get {
return 计算后属性值
}
set (新属性值) {
......
}
}
}
enum 枚举名 {
static var (或let) 存储属性 = "xxx"
......
static var 计算属性名 : 属性数据类型 {
get {
return 计算后属性值
}
set (新属性值) {
......
}
}
}
class 类名 {
......
class var 计算属性名 : 属性数据类型 {
get {
return 计算后属性值
}
set (新属性值) {
......
}
}
}
结构体中可以定义静态存储属性和计算属性;定义静态存储属性,声明关键字是static,这个属性可以是变量属性也可以是常量属性;定义静态计算属性,声明使用的关键字是static,计算属性不能为常量。结构体静态计算属性也可以是只读的,语法如下:
static var 计算属性名 : 属性数据类型 {
return 计算后属性值
}
定义枚举,枚举中不可以定义实例存储属性,但可以定义静态存储属性,也可以定义静态计算属性。定义枚举静态属性与定义结构体静态属性的语法完全一样。
定义类,类中可以定义实例存储属性,但不可以定义静态存储属性。类中可以定义静态计算属性。声明使用的关键字是class,这与结构体和枚举的声明不同。
归纳:
| 面向对象类型 | 实例存储属性 | 静态存储属性 | 实例计算属性 | 静态计算属性 |
|---|---|---|---|---|
| 类 | 支持 | 不支持 | 支持 | 支持 |
| 结构体 | 支持 | 支持 | 支持 | 支持 |
| 枚举 | 不支持 | 支持 | 支持 | 支持 |
提示:在静态计算属性中不能访问实例属性(包括存储属性和计算属性),但可以访问其他静态属性。在实例计算属性中能访问实例属性,也能访问静态属性。
结构体静态属性
struct Account {
var amount : Double = 0.0 //账户金额
var owner : String = "" //账户名
static var interestRate : Double = 0.668 //利率
static var staticProp : Double {
return interestRate * 1_000_000
}
var instanceProp : Double {
return Account.interestRate * amount
}
}
//访问静态属性
print(Account.staticProp)
var myAccount = Account()
//访问实例属性
myAccount.amount = 1_000_000
//访问实例属性
print(myAccount.instanceProp)
上述代码定义了Account结构体,static var interestRate : Double = 0.668定义了静态存储属性interestRate,代码 static var staticProp : Double { return interestRate * 1_000_000 }定义了静态计算属性staticProp,在其属性体中可以访问interestRate等静态属性。代码var instanceProp : Double { return Account.interestRate * amount }定义了实例计算属性instanceProp,在其属性体中能访问静态属性interestRate,访问方式为“类型名.静态属性”。访问实例属性访问方式是“实例.实例属性”。
枚举静态属性
enum Account {
case 中国银行
case 中国工商银行
case 中国建设银行
case 中国农业银行
static var interestRate : Double = 0.668
static var staticProp : Double {
return interestRate * 1_000_000
}
var instanceProp : Double {
switch (self) {
case 中国银行:
Account.interestRate = 0.667
case 中国工商银行:
Account.interestRate = 0.669
case 中国建设银行:
Account.interestRate = 0.666
case .中国农业银行:
Account.interestRate = 0.668
}
return Account.interestRate * 1_000_000
}
}
//访问静态属性
print(Account.staticProp)
var myAccount = Account.中国工商银行
//访问实例属性
print(myAccount.instanceProp)
类静态属性
class Account {
var amount : Double = 0.0 //账户金额
var owner : String = "" //账户名
var interestRate : Double = 0.668 //利率
class var staticProp : Double {
return 0.668 * 1_000_000
}
var instanceProp : Double {
return self.interestRate * self.amount
}
}
//访问静态属性
print(Account.staticProp)
var myAccount = Account()
//访问实例属性
myAccount.amount = 1_000_000
//访问静态属性
print(myAccount.instanceProp)
注意在类中不能定义静态存储属性。代码class var staticProp : Double 定义了静态计算属性staticProp,关键字是class。self指代当前实例本身。
使用下标
在访问数组和字典的时候,可以采用下标访问。其中数组的下标是整数类型索引,字典的下标是它的"键"。
下标概念 在Swift中,可以定义一些集合类型,它们可能会有一些集合类型的存储属性,这些属性中的元素可以通过下标访问。Swift中的下标相当于Java中的索引属性和C#中的索引器。
下标访问的语法格式如下:
面向对象类型 类型名 {
其他属性
......
subscript(参数: 参数数据类型) -> 返回值数据类型 {
get {
return 返回值
}
set (新属性值) {
......
}
}
}
“面向对象类型”包括类、结构体和枚举3种。下标采用subscript关键字声明。下标也有类似于计算属性的getter和setter访问器。
示例: 二维数组 在Swift中没有提供二维数组,只有一维数组Array。可以自定义一个二维数组类型,然后通过两个下标参数访问它的元素,形式上类似于C语言的二维数组。
采用下标的二维数组示例代码如下:
struct DoubleDimensionalArray {
let rows : Int, columns : Int
var grid : [Int]
init(rows: Int, columns: Int) {
self.rows = rows
self.columns = columns
grid = Array(count:rows * columns, repeatedValue:0)
}
subscript(row: Int, col: Int) -> Int {
get {
return grid[(row * columns) + col]
}
set (newValue1) {
grid[(row * columns) + col] = newValue1
}
}
}
let COL_NUM = 10
let ROW_NUM = 10
var ary2 = DoubleDimensionalArray(rows: ROW_NUM, columns: COL_NUM)
for i in 0 ..< ROW_NUM {
for j in 0 ..< COL_NUM {
ary2[i,j] = i * j
}
}
for i in 0 ..< ROW_NUM {
for j in 0 ..< COL_NUM {
print("\t \(ary2[i,j])")
}
print("\n")
}