Swift 屬性
前言
屬性也叫類的成員變量,成員變量不能獨立於類而存在,成員變量是描述類的對象的狀態數據。
- 屬性就是類所表示的現實對象的特性在代碼中的反應。
- 在 Swift 語言中實例屬性的類型分為兩種,存儲屬性和計算屬性。
- 在 Swift 語言中還有一種屬性是類型屬性,類型屬性不屬於任何一個類的實例,而是屬於類本身。
1、存儲屬性
存儲屬性把常量或變量的值作為實例的一部分。
- 存儲屬性只能用於類和結構體裏。
- 存儲屬性也分為變量屬性和常量屬性,分別用關鍵字
var
和關鍵字let
來描述。 - 在 OC 中,類的屬性會有對應的實例變量,比如屬性
a
對應的實例變量默認為_a
,而 Swift 中把二者統一了起來。
存儲屬性中的常量屬性並不意味著絕對不能變化,而是要看情況。
- 如果存儲屬性的常量屬性是值類型,比如字符串、結構體,就不能再變,結構體的屬性也不能再變。
- 如果存儲屬性的常量屬性是引用類型,如類,那麽就可能重新賦值。
在 Swift 中,類在初始化的時候它的存儲屬性必須都被初始化。
- 如果初始化也不定義默認值,在調用
super.init()
時會出錯,或者在聲明了對象之後,也無法為此變量賦值。 如果不想設置某個屬性的默認值,可以使用
?
把它加入可選鏈中,或者使用!
把它定義為隱式解包可選,也就是把它聲明為可選型。class Student { var name: String? var age: Int = 10 }
- 如果初始化也不定義默認值,在調用
2、計算屬性
計算屬性本身並不直接存儲特性,提供的是一個計算後的結果,類似於方法的功能,提供了一個處理數據的入口與出口。
- 計算屬性可以用於類、枚舉和結構體裏。
- 計算屬性(包含只讀計算屬性)都應該使用
var
關鍵字,因為他們的值並不是固定的。 在計算屬性中可以使用
getter
和可選的setter
來間接的獲得或者改變其他的屬性和值。var/let 計算屬性名稱: 類型 { get { // 返回屬性的值 } set(newValue) { // 執行賦值操作 } }
屬性類型
- 使用計算屬性時一定要聲明屬性的類型,否則編譯器會報錯。
get 方法
- 在計算屬性中可以定義
get
方法和set
方法,其中set
方法不是必須的。 - 如果計算屬性中沒有寫
set
方法,則可以把get
方法中的內容直接寫到計算屬性的方法體中,從而省略外面的get{}
。
- 在計算屬性中可以定義
set 方法
- 在計算屬性中可以定義
get
方法和set
方法,其中set
方法不是必須的。 set
方法有一個默認的參數newValue
,用來表示傳入的新值。- 即便不在參數列表中顯示的寫出
newValue
,依舊可以在set
方法中使用newValue
。 - 可以在參數列表中寫上其它名字以替換默認的參數名
newValue
。
- 在計算屬性中可以定義
定義計算屬性時直接在屬性類型後面的大括號
{}
中設置set
和get
方法,不需要設置初始值。class Student { var givenName = "" var firstName = "" var allName: String { get { return givenName + firstName } set { firstName = newValue } } }
3、類型屬性
可以定義一種屬性,這種屬性不屬於任何一個類的實例,即不屬於任何一個對象,它只屬於類本身,這樣的屬性就稱為類型屬性。
- 即使創建再多的這個類的實例,這個屬性也不屬於任何一個,它只屬於類本身。
- 類型屬性可以用於定義特定類型所有實例共享的數據。
- 類型屬性可以包括存儲屬性和計算屬性。
- 使用關鍵字
static
定來義類型屬性。 - 在類中用關鍵字
class
來定義被重寫的計算屬性。 - 類型屬性在使用時直接使用類型本身來調用。
類中的類型屬性定義示例
class NewClass { // 定義存儲類型屬性 static var storedTypeProperty = "someValue" // 定義計算類型屬性 static var computedTypeProperty: Int { // get、set 方法 return 0 } // 重寫計算類型屬性 class var overrideableComputedTypeProperty: Int { // get、set 方法 return 1 } } print(NewClass.storedTypeProperty) // "someValue" print(NewClass.computedTypeProperty) // 0 print(NewClass.overrideableComputedTypeProperty) // 1
結構體中的類型屬性示例
struct NewStruct { // 定義存儲類型屬性 static var storedTypeProperty = "someValue" // 定義計算類型屬性 static var computedTypeProperty: Int { // get、set 方法 return 0 } } print(NewStruct.storedTypeProperty) // "someValue" print(NewStruct.computedTypeProperty) // 0
枚舉中的類型屬性示例
enum NewEnum { // 定義存儲類型屬性 static var storedTypeProperty = "someValue" // 定義計算類型屬性 static var computedTypeProperty: Int { // get、set 方法 return 0 } } print(NewEnum.storedTypeProperty) // "someValue" print(NewEnum.computedTypeProperty) // 0
4、懶加載
存儲屬性一般要求初始化,我們可以設置一個
lazy
修飾符,使得這種初始化被延遲,盡管我們在屬性聲明時已經做了這種初始化上的定義。lazy
修飾的存儲屬性叫 “懶惰存儲屬性(懶加載)”。- 懶惰存儲屬性的初始值直到實例初始化完成之後,在調用之時才被計算。
- 懶惰存儲屬性必須是變量屬性,即用
var
定義的屬性,常量屬性不能夠被聲明為懶惰存儲屬性,常量屬性在實例初始化完成之前就應該被賦值。 - 懶惰存儲屬性依舊遵循類在初始化的時候所有屬性必須初始化的規則,並且必須設置默認值。
在全局變量中不需要顯式的指定 lazy 屬性,而是所有的全局變量都是延遲計算的。
lazy var name: String? = "xiaoming"
lazy var shops: NSArray = { let filePath: String = Bundle.main.path(forResource: "shops", ofType: "plist")! let tmp = NSArray(contentsOfFile: filePath)! return tmp }()
所謂修飾符就是加在變量、函數、類等的定義前面,用來約束或者增強變量、函數、類功能的一種特殊的關鍵字。比如修飾符
@objc
表示導出給 OC 調用。
5、屬性觀察者
屬性觀察者更像是觸發器,可以用來觀察屬性值的變化,不過屬性觀察者同觸發器不同的是,還可以在屬性變更前觸發。
- 屬性觀察者觀察屬性值的改變並對此作出響應。
- 當設置屬性的值時,屬性觀察者會被調用,即使當新值同原值相同時也會被調用。
- 除了懶惰存儲屬性,你可以為任何存儲屬性加上屬性觀察者定義。
- 通過重寫子類型屬性,也可以為繼承的屬性(存儲或計算)加上屬性觀察者定義。
屬性觀察者更適合值類型,屬性觀察者實際上監聽的是 “棧” 上所發生的改變。
var/let 屬性名: 類型 = 默認值 { willSet { // 在屬性更改之前做某些操作 } didSet { // 在屬性更改之後做某些操作 } }
屬性類型
- 給屬性添加觀察者時必須要聲明清楚屬性的類型,否則編譯器報錯。
willSet 方法
willSet
方法有一個默認的參數newValue
,用來表示傳入的新值。- 即便不在參數列表中顯示的寫出
newValue
,依舊可以在willSet
方法中使用newValue
。 - 可以在參數列表中寫上其它名字以替換默認的參數名
newValue
。
didSet 方法
didSet
方法有一個默認的參數oldValue
,用來表示之前的舊值。- 即便不在參數列表中顯示的寫出
oldValue
,依舊可以在didSet
方法中使用oldValue
。 - 可以在參數列表中寫上其它名字以替換默認的參數名
oldValue
。
屬性初始化時,
willSet
和didSet
並不會被調用。只有在初始化上下文時,當設置屬性值時才被調用。willSet
和didSet
每次設置屬性值都會被調用,即使是設置的值和原來的值相同。class Student { var name: String = "xiaoming" var age: Int = 0 { willSet { print(name + "old: \(age)") print(name + "new: \(newValue)") } didSet { print(name + "old: \(oldValue)") print(name + "new: \(age)") } } }
在 iOS 開發中屬性觀察者常用的地方就是更新用戶界面(UI),比如對頁面上的某些屬性做了修改,那麽就需要早
didSet
方法中對用戶界面進行更新。
Swift 屬性