-
存储属性
-
计算属性
-
属性观察者
-
静态属性
-
使用下标
存储属性
存储属性概念
存储属性可以存储数据,分为常量属性(用关键字let定义)和变量属性(用关键字var定义)。存储属性适用于
类和结构体
两种Swift面向对象类型。
注意:存储属性适用于类和结构体,不适用于枚举类型。
这些属性要么在构造函数中去赋予初始值,要么在定义的时候去赋予初始值,如下图:
struct Department {
var no: Int = 0
var name: String = "SALES"
init() {
self.no = 0
self.name = ""
}
}
看看下面的代码
class Employee {
var no: Int = 0
var name: String = "Tony"
var job: String?
var salary: Double = 0
var dept: Department? = Department()
}
struct Department {
var no: Int = 0
var name: String = "SALES"
}
let emp = Employee()
emp.no = 100
emp.name = "top"
let dept = Department()
dept.name = "SALES" //编译错误
如下图:Department被声明为let会报错
原因解释:
Employee是类这种类型,即引用数据类型,引用数据类型实际上是一种指针类型,对指针声明为let没有关系,这就是所谓的像C++语言中的指针常量类型,这种常量类型可以保证指针本身不被修改,但是指针所指的内容可以被修改。
Department是一个结构体,结构体是值类型,值类型被声明成let后就不能被修改。
注意:引用类型相当于指针,emp相当于常量指针,常量指针是不可能修改的,但是它所指向的内容可以修改。而常量值类型dept, 无论是结构体还是枚举类型都不能被修改。
延迟存储属性
或许我们不关心员工隶属于哪个部门,只关心他的no(编号)和name(姓名)。虽然不使用dept实例,但仍然会占用内存。Swift采用了延迟加载
技术。
//延迟存储属性
class Employee2 {
var no: Int = 0
var name: String = "Tony"
var job: String?
var salary: Double = 0
lazy var dept: Department2 = Department2()
}
struct Department2 {
var no: Int = 0
var name: String = ""
}
let emp2 = Employee2()
emp2.no = 100
emp2.name = "Martin"
emp2.job = "Sale"
emp2.salary = 5000
print(emp2.dept.no)
emp2
Employee2中的dept使用了延迟加载后,在 print(emp2.dept.no)这段代码前,emp2中的dept值为nil
在 print(emp2.dept.no)这段代码后,emp2中的dept有具体的值
计算属性
计算属性概念
计算属性本身不存储数据,而是从其他存储属性中计算得到数据。与存储属性不同,
类、结构体和枚举都可以定义计算属性
。
计算属性语法格式
面向对象类型 类型名 {
存储属性
...
var 计算属性名 : 属性数据类型 {
get {
return 计算属性值
}
set ( 新属性值) {
...
}
}
}
class Employee3 {
var no: Int = 0
var firstName: String = "张"
var lastName: String = "三"
var job: String?
var salary: Double = 0
lazy var dept: Department3 = Department3()
var fullName: String {
get {
return firstName + "." + lastName
}
set {
//newValue是由系统提供的名字,也就是传进来的值,即 emp3.fullName = "李.四"中的李四
//newValue 本质是String--> NSString (桥接)
var name = newValue.components(separatedBy: ".")
firstName = name[0]
lastName = name[1]
}
}
}
struct Department3 {
var no: Int = 0
var name: String = ""
}
let emp3 = Employee3()
print(emp3.fullName)
emp3.fullName = "李.四"
print(emp3.fullName)
注: newValue是由系统提供的名字,也就是传进来的值,即 emp3.fullName = "李.四"中的李四
也可以不用系统的newValue,自定义一个参数名为newFullName
如下面的代码,把上面的set部分改为下面的样式
//也可以不用系统的newValue,自定义一个参数名为newFullName
set (newFullName) {
var name = newFullName.components(separatedBy: ".")
firstName = name[0]
lastName = name[1]
}
计算属性的只读属性
未省略时
var fullName: String {
get {
return firstName + "." + lastName
}
}
省略时
var fullName: String {
return firstName + "." + lastName
}
结构体中的计算属性
结构体中定义属性和类中没有本质的区别
struct Department3 {
var no: Int = 0
var name: String = ""
var fullName: String {
return "研发部." + "业务支持中心"
}
}
print(emp3.dept3.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中的属性观察者主要有以下两个
- willSet: 观察者在修改之前调用。
- didSet: 观察者在修改之后立刻调用。
注意: 属性观察者不能监听延迟存储属性和常量存储属性的变化。
属性观察者的语法格式
面向对象类型 类型名 {
...
var 存储属性: 属性数据类型 = 初始化值 {
willSet (新值) {
...
}
didSet ( 旧值) {
...
}
}
}
注:不指定新值和旧值,系统会自动分配一个newValue 或oldValue
。
//属性观察者
class Employee4 {
var no: Int = 0
var name: String = "Lucy" {
willSet (newNameValue) {
print("员工name新值:\(newNameValue)")
}
didSet(oldNNameValue) {
print("员工name旧值:\(oldNNameValue)")
}
}
var job: String?
var salary: Double = 0
var dept: Department4?
}
struct Department4 {
var no: Int = 10 {
willSet {
print("部门编号新值:\(newValue)")
}
didSet {
print("部门编号旧值:\(oldValue)")
}
}
var name: String = "销售部门"
}
let emp4 = Employee4()
emp4.no = 100
emp4.name = "Lily"
var dept = Department4()
dept.no = 30
输出结果如下:
静态属性
实例属性隶属于某一个实例,而静态属性隶属于具体的类型,属于这个类型下面的所有的实例。
静态属性的概念
有一个Account(银行账户)类,假设它有3个属性:amount(账户金额)、interestRate(利率)和owner(账户名)。在这3个属性中,amount和owner会因人而异,不同的账户这些内容是不同的,而所有账户的interestRate都是相同的。
amount和owner属性与账户个体有关,称为实例属性
。interestRate属性与个体无关,或者说是所有账户个体共享的,这种属性称为静态属性
或类型属性
。
结构体静态属性语法格式
struct 结构体名 {
static var(或let) 存储属性 = "xxx"
...
static var 计算属性名 : 属性数据类型 {
get {
return 计算后属性值
}
set ( 新属性值) {
...
}
}
}
枚举静态属性语法格式
enum 枚举名 {
static var(或let) 存储属性 = "xxx"
...
static var 计算属性名 : 属性数据类型 {
get {
return 计算后属性值
}
set ( 新属性值) {
...
}
}
}
类静态属性语法格式
class 类名 {
static var(或let) 存储属性 = "xxx"
...
class(或static) var 计算属性名 : 属性数据类型 {
get {
return 计算后属性值
}
set ( 新属性值) {
...
}
}
}
类静态属性
类中不仅可以定义实例存储属性,还可以定义静态存储属性,声明静态存储属性的关键字是static。
类中也可以定义静态计算属性,声明使用的关键字是class或static。类静态计算属性如果使用static定义,则该属性不能在子类中被重写(override); 如果使用class定义,则该属性可以被子类重写。
结构体静态属性代码
//结构体静态属性
struct Account {
var amount: Double = 0.0 //账户金额
var owner: String = "" //账户名
static var interestRate: Double = 0.0668 //利率 静态存储属性
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)
枚举静态属性代码
//枚举静态属性(不可以定义实例存储属性)
enum Account2 {
case 中国银行
case 中国工商银行
case 中国建设银行
case 中国农业银行
static var interestRate: Double = 0.0668 //利率 静态存储属性
static var staticProp: Double {
return interestRate * 1_000_000 //静态计算属性
}
var instanceProp: Double {
switch (self) {
case .中国银行:
Account2.interestRate = 0.667
case .中国工商银行:
Account2.interestRate = 0.669
case .中国建设银行:
Account2.interestRate = 0.666
case .中国农业银行:
Account2.interestRate = 0.668
}
return Account2.interestRate * 1_000_000
}
}
//访问静态属性
print(Account2.staticProp)
var myAccount2 = Account2.中国银行
//访问静态属性
print(myAccount2.instanceProp)
注:枚举不可以定义实例存储属性,可以定义静态存储属性
类的静态属性代码
//类的静态属性
class Account3 {
var amount: Double = 0.0 //账户金额
var owner: String = "" //账户名
static let interestRate : Double = 0.0668 //利率 静态存储属性
class var staticProp: Double {
return interestRate * 1_000_000
}
var interestRate: Double {
return Account3.interestRate * self.amount
}
}
//子类覆盖父类的计算属性
class A: Account3 {
override class var staticProp: Double {
return interestRate * 1_000_000
}
}
class B: A {
override class var staticProp: Double {
return interestRate * 1_000_000
}
}
print(Account3.staticProp)
var myAccount3 = Account()
//访问实例属性
myAccount3.amount = 1_000_000
//访问静态属性
print(myAccount3.instanceProp)
注意: 下面的这个部分的静态存储属性 只能用static声明。
static let interestRate : Double = 0.0668 //利率
注意: 下面的这个部分的静态计算属性,如果没有子类需要重写当前类可以使用static和class声明,如果有子类需要重写当前类必须使用class声明。
class var staticProp: Double {
return interestRate * 1_000_000
}
归纳面向对象类型属性 如下图:
注意:
1、在静态计算属性中不能访问实例属性(包括存储属性和计算属性), 但可以访问其他静态属性
。
如下图:在静态计算属性staticProp中不能访问实例属性amount(存储属性)和owner(存储属性),也不能访问实例属性instanceProp(计算属性)
2、在实例计算属性中能访问实例属性,也能访问静态属性。
如下图:在实例计算属性instanceProp中 既可以访问实例属性amount,也可以访问静态属性interestRate。
使用下标
在Swift语言中只有一维数组,没有二维数组。如果需要用到二维数组,就可以用下标。
数组和字典中使用下标
//下标
var studentList: [String] = ["张三", "李四", "王五"]
studentList[0] = "诸葛亮"
var studentDictionary = ["102": "张三", "105": "李四", "109": "王五"]
studentDictionary["110"] = "董六"
下标访问语法格式
面向对象类型 类型名 {
其他属性
...
subscript(参数:参数数据类型) ->返回值数据类型 {
get {
return 返回值
}
set ( 新属性值) {
...
}
}
}
struct DoubleDimensionalArray {
let rows: Int, columns: Int
var grid: [Int]
init(rows: Int, columns: Int) {
self.rows = rows
self.columns = columns
grid = Array(repeating: 0, count: rows * columns)
}
subscript(row: Int, col : Int) -> Int {
get {
return grid[(row * columns) + col]
}
set (newValue) {
grid[(row * columns) + col] = newValue
}
}
}
let COL_NUM = 10
let ROW_NUM = 10
var array2 = DoubleDimensionalArray(rows: ROW_NUM, columns: COL_NUM)
for i in 0 ..< ROW_NUM {
for j in 0 ..< COL_NUM {
array2[i, j] = i * j
}
}
for i in 0 ..< ROW_NUM {
for j in 0 ..< COL_NUM {
print("\t \(array2[i, j])", terminator: "")
}
print("\n")
}