什么是初始化
初始化就是:給存儲屬性賦值。像下面這樣
struct Fahrenheit {
var temperature: Double
init() {
temperature = 32.0
}
}
注意:當你對給一個屬性分配一個默認值的時候,它會調用它相對應的初始化方法,這個值是對屬性直接設置的,不會通知它對應的觀察者。
下面有2種初始化方法:
- 默認初始化方法
Swift為每一個結構或者基類提供了默認的構造器,來初始化它們所包含的所有屬性。默認構造器將會創建一個新的實例然后將它們的屬性設置為默認值。
class ShoppingListItem {
var name: String?
var quantity = 1
var purchased = false
}
var item = ShoppingListItem()
- 自定義初始化
你可以根據輸入的參數來自定義初始化過程和可選的屬性類型,或者在初始化的時候修改靜態屬性。
帶參數的初始化方法叫自定義初始化。
struct Celsius {
var temperatureInCelsius: Double = 0.0
init(fromFahrenheit fahrenheit: Double) {
temperatureInCelsius = (fahrenheit - 32.0) / 1.8
}
init(fromKelvin kelvin: Double) {
temperatureInCelsius = kelvin - 273.15
}
}
當然上面只是基礎知識幾個概念,下面才是重點。
類的繼承及其初始化
- 類的初始化過程
兩段式構造過程
Swift 中類的構造過程包含兩個階段。第一個階段,每個存儲型屬性通過引入它們的類的構造器來設置初始值。當每一個存儲型屬性值被確定后,第二階段開始,它給每個類一次機會在新實例準備使用之前進一步定制它們的存儲型屬性。
階段 1
某個指定構造器或便利構造器被調用;
完成新實例內存的分配,但此時內存還沒有被初始化;
指定構造器確保其所在類引入的所有存儲型屬性都已賦初值。存儲型屬性所屬的內存完成初始化;
指定構造器將調用父類的構造器,完成父類屬性的初始化;
這個調用父類構造器的過程沿著構造器鏈一直往上執行,直到到達構造器鏈的最頂部;
當到達了構造器鏈最頂部,且已確保所有實例包含的存儲型屬性都已經賦值,這個實例的內存被認為已經完全初始化。此時階段1完成。
階段 2
從頂部構造器鏈一直往下,每個構造器鏈中類的指定構造器都有機會進一步定制實例。構造器此時可以訪問self、修改它的屬性并調用實例方法等等。
最終,任意構造器鏈中的便利構造器可以有機會定制實例和使用self。
- 如何初始化
1、自定義初始化方法要先調用自己類默認初始化方法,自己重寫默認初始化方法要先調用父類默認初始化方法
2、應該要先調用父類的構造器或者自身的默認構造器,以防止先給屬性賦值了然后才調用父類或者自身的默認構造器把以前的賦值覆蓋了
- 關于初始化的繼承
規則 1
如果子類沒有定義任何指定構造器,它將自動繼承所有父類的指定構造器。
規則 2
如果子類提供了所有父類指定構造器的實現--不管是通過規則1繼承過來的,還是通過自定義實現的--它將自動繼承所有父類的便利構造器。
- Swift的4種安全檢查
安全檢查 1
指定構造器必須保證它所在類引入的所有屬性都必須先初始化完成,之后才能將其它構造任務向上代理給父類中的構造器。
安全檢查 2
指定構造器必須先向上代理調用父類構造器,然后再為繼承的屬性設置新值。如果沒這么做,指定構造器賦予的新值將被父類中的構造器所覆蓋。
安全檢查 3
便利構造器必須先代理調用同一類中的其它構造器,然后再為任意屬性賦新值。如果沒這么做,便利構造器賦予的新值將被同一類中其它指定構造器所覆蓋。
安全檢查 4
構造器在第一階段構造完成之前,不能調用任何實例方法、不能讀取任何實例屬性的值,也不能引用self的值。
代碼實例
class Food {
var name: String
//指定的初始化器
init(name: String) {
self.name = name
}
//便攜初始化器
convenience init() {
self.init(name: "[Unnamed]")
}
}
class RecipeIngredient: Food {
var quantity: Int
//重載指定初始化器
init(name: String, quantity: Int) {
//首先初始化自己本類的存儲屬性
self.quantity = quantity
//然后調用初始化父類的存儲屬性
super.init(name: name)
}
convenience init(name: String) {
self.init(name: name, quantity: 1)
}
}
class ShoppingListItem: RecipeIngredient {
var purchased = false
var description: String {
var output = "\(quantity) x \(name.lowercaseString)"
output += purchased ? " ?" : " ?"
return output
}
}
由于它為自己引入的所有屬性都提供了默認值,并且自己沒有定義任何構造器,ShoppingListItem將自動繼承所有父類中的指定構造器和便利構造器。