屬性將值跟特定的類(lèi)、結(jié)構(gòu)或枚舉關(guān)聯(lián)。
-
存儲(chǔ)屬性: 存儲(chǔ)常量或變量作為實(shí)例的一部分。
- 計(jì)算屬性可以用于 類(lèi)、結(jié)構(gòu)體 和 枚舉
-
計(jì)算屬性: 計(jì)算(不是存儲(chǔ))一個(gè)值。
- 存儲(chǔ)屬性只能用于 ** 類(lèi)** 和 結(jié)構(gòu)體。*
屬性分為 實(shí)例屬性 和 類(lèi)型屬性
1. 存儲(chǔ)屬性
存儲(chǔ)屬性:就是存儲(chǔ)在特定類(lèi)或結(jié)構(gòu)體實(shí)例里的一個(gè) 常量 或 變量。
- 變量存儲(chǔ)屬性(用關(guān)鍵字 var 定義)
- 常量存儲(chǔ)屬性(用關(guān)鍵字 let 定義)
** 存儲(chǔ)屬性的默認(rèn)值 **
- 存儲(chǔ)屬性可以在定義的時(shí)候賦值默認(rèn)值。
- 可以在構(gòu)造過(guò)程中設(shè)置和修改存儲(chǔ)屬性的值。(常量的值只可以在構(gòu)造函數(shù)中進(jìn)行修改)
常量結(jié)構(gòu)體的存儲(chǔ)屬性
創(chuàng)建了一個(gè)結(jié)構(gòu)體的實(shí)例并將其賦值給一個(gè)常量,則無(wú)法修改該實(shí)例的任何屬性,即使有屬性被聲明為變量也不行。
(常量結(jié)構(gòu)體的變量屬性是不能被修改的,這個(gè)是由于結(jié)構(gòu)體的值類(lèi)型決定)
** 延遲存儲(chǔ)屬性**
延遲存儲(chǔ)屬性是指 當(dāng)?shù)谝淮伪徽{(diào)用的時(shí)候 才會(huì)計(jì)算其 初始值 的屬性。在屬性聲明前使用 lazy 來(lái)標(biāo)示一個(gè)延遲存儲(chǔ)屬性。
- 延遲存儲(chǔ)屬性必須用 var 聲明
- 被標(biāo)記為 lazy 的屬性在沒(méi)有初始化時(shí)就同時(shí)被多個(gè)線程訪問(wèn),則無(wú)法保證該屬性只會(huì)被初始化一次。(加鎖)
實(shí)例屬性使用場(chǎng)景
- 屬性值對(duì)實(shí)例的構(gòu)造過(guò)程不依賴(lài)
- 屬性的值需要經(jīng)過(guò)大量計(jì)算才可以得到(耗時(shí))
(加載本地文件數(shù)據(jù)就可以使用延遲屬性)
2. 計(jì)算屬性
- ** 計(jì)算屬性不直接存儲(chǔ)值,**而是提供一個(gè) getter 和一個(gè)可選的 setter,來(lái)間接獲取和設(shè)置其他屬性或變量的值。
- 計(jì)算屬性只能用 var 來(lái)聲明。(由于計(jì)算屬性值的不確定性決定)
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()
// 計(jì)算屬性, 中心點(diǎn)是依賴(lài) origin 和 size 計(jì)算得出具體的值。本身不能保存值。
var center: Point {
// getter
get {
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
// setter (可選的)
/**
set 方法默認(rèn)有一個(gè)參數(shù) newValue 用來(lái)表示我們傳入的值。
我可以對(duì)set 的參數(shù)名稱(chēng)進(jìn)行進(jìn)行修改,增強(qiáng)代碼的可讀性。
這個(gè)是 編輯 set 聲明的使用,直接使用 newValue 并且 set 的參數(shù)可以省略。
set {
origin.x = newValue.x - (size.width / 2)
origin.y = newValue.y - (size.height / 2)
}
*/
set(newCenter) {
origin.x = newCenter.x - (size.width / 2)
origin.y = newCenter.y - (size.height / 2)
}
}
}
只讀計(jì)算屬性:
只有 getter 沒(méi)有 setter 的計(jì)算屬性就是只讀計(jì)算屬性。
(只讀計(jì)算屬性總是返回一個(gè)固定的值,不能賦新值)
struct Cuboid {
var width = 0.0, height = 0.0, depth = 0.0
// 只讀計(jì)算屬性,可以省略 get 個(gè)花括號(hào)
var volume: Double {
return width * height * depth
}
}
3. 屬性觀察器(存儲(chǔ)屬性和計(jì)算屬性都可以添加屬性觀察器)
屬性觀察器監(jiān)控和響應(yīng)屬性值的變化,每次屬性被設(shè)置值的時(shí)候都會(huì)調(diào)用屬性觀察器,即使新值和當(dāng)前值相同。
- 延遲存儲(chǔ)屬性 不能有 屬性觀察器。(重點(diǎn))
- 可以通過(guò) 重寫(xiě) 屬性的方式為 繼承的屬性(包括存儲(chǔ)屬性和計(jì)算屬性)添加屬性觀察器。
- 可以給所有的存儲(chǔ)屬性添加屬性觀察器。
- 不必為 非重寫(xiě) (非繼承) 的 ** 計(jì)算屬性 ** 添加屬性觀察器,因?yàn)榭梢酝ㄟ^(guò)它的 setter 直接監(jiān)控和響應(yīng)值的變化。
理論上屬性觀察器是可以給所有的屬性添加。(不用區(qū)分是否是存儲(chǔ)是否是計(jì)算。主要是要區(qū)分一下使用的場(chǎng)景)
可以為屬性添加如下一個(gè)或多個(gè)屬性觀察器:
- willSet: 在新的值被設(shè)置之前調(diào)用
- willSet 觀察器會(huì)將新的屬性值作為 常量參數(shù) 傳入。
在 willSet 的實(shí)現(xiàn)代碼中可以為這個(gè)參數(shù)指定一個(gè)名稱(chēng),不指定可以使用默認(rèn)參數(shù) newValue。
- willSet 觀察器會(huì)將新的屬性值作為 常量參數(shù) 傳入。
- didSet: 在新的值被設(shè)置之后調(diào)用
- didSet 觀察器會(huì)將舊值作為參數(shù)傳入。
在 didSet 的實(shí)現(xiàn)代碼中可以為這個(gè)參數(shù)指定一個(gè)名稱(chēng), 不指定可以使用默認(rèn)的參數(shù) oldValue
- didSet 觀察器會(huì)將舊值作為參數(shù)傳入。
class StepCounter {
// 這是一個(gè)存儲(chǔ)屬性
var totalSteps: Int = 0 {
// willSet 屬性觀察器 , 指定的傳入?yún)?shù)名稱(chēng)為 newTotalSteps。
/*
// 這個(gè)為使用默認(rèn)參數(shù)
willSet {
print("About to set totalSteps to \(newValue)")
}
*/
willSet(newTotalSteps) {
print("About to set totalSteps to \(newTotalSteps)")
}
/*
// 自己定義一個(gè)參數(shù)使用,主要是為了代碼的語(yǔ)義化。
didSet ( tempOldValue ) {
// totalSteps 就是屬性本身。
if totalSteps > tempOldValue {
print("Added \(totalSteps - tempOldValue) steps")
}
}
*/
// 這個(gè)為使用默認(rèn)參數(shù)
didSet {
if totalSteps > oldValue {
print("Added \(totalSteps - oldValue) steps")
}
}
}
}
存儲(chǔ)屬性的使用注意:
- 父類(lèi)的屬性在子類(lèi)中賦值時(shí),父類(lèi)的 屬性觀察器會(huì)先被調(diào)用,后才會(huì)調(diào)用子類(lèi)的屬性觀察器。
- 在父類(lèi)初始化方法調(diào)用之前,子類(lèi)給屬性賦值時(shí),觀察器不會(huì)被調(diào)用。
- 屬性是通過(guò) in-out 方式傳入, 屬性觀察器也會(huì)被調(diào)用。
* in-out 是用的是值的拷貝使用, 使用的是值的拷貝,值使用完畢后再將值拷貝出來(lái)。
4. 全局變量 和 局部變量
全局變量:是在函數(shù)、方法、閉包或任何類(lèi)型之外定義的變量。
局部變量:是在函數(shù)、方法或閉包內(nèi)部定義的變量。
全局或局部變量都屬于存儲(chǔ)型變量,跟存儲(chǔ)屬性類(lèi)似,它為特定類(lèi)型的值提供存儲(chǔ)空間,并允許讀取和寫(xiě)入。
在全局或局部范圍都可以定義計(jì)算型變量和為存儲(chǔ)型變量定義觀察器。計(jì)算型變量跟計(jì)算屬性一樣,返回一個(gè)計(jì)算結(jié)果而不是存儲(chǔ)值,聲明格式也完全一樣。
注意:
全局的常量或變量都是延遲計(jì)算的,跟延遲存儲(chǔ)屬性相似,不同的地方在于,全局的常量或變量不需要標(biāo)記lazy修飾符。
局部范圍的常量或變量從不延遲計(jì)算。
5. 類(lèi)型屬性
實(shí)例屬性: 特定類(lèi)型的實(shí)例的屬性叫實(shí)例屬性。實(shí)例之間的屬性是相互獨(dú)立的。
類(lèi)型屬性:特定類(lèi)型的屬性叫實(shí)例屬性。類(lèi)型之間的屬性是共享的。只有唯一一份。
(類(lèi)型屬性: 特么第一眼我也沒(méi)看明白。其實(shí)就是特么寫(xiě)在類(lèi)里面的靜態(tài)變量和靜態(tài)常量)
使用 static 來(lái)定義類(lèi)型屬性(靜態(tài)變量和靜態(tài)常量)。
定義計(jì)算型類(lèi)型屬性,可以改用 class 來(lái)支持子類(lèi)對(duì)父類(lèi)實(shí)現(xiàn)進(jìn)行重寫(xiě)。
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 表示不允許子類(lèi)重寫(xiě)
static var computedTypeProperty: Int {
return 27
}
// 使用 class 表示允許子類(lèi)重寫(xiě)。
class var overrideableComputedTypeProperty: Int {
return 107
}
}