構(gòu)造方法是一個類創(chuàng)建對象最先也是必須調(diào)用的方法,在Swift語言體系中,構(gòu)造方法與普通的方法分界十分嚴(yán)格,從格式寫法上就有不同,普通方法函數(shù)要以func聲明,構(gòu)造方法統(tǒng)一為init命名,不需要func關(guān)鍵字聲明。
接下來簡單介紹下swift中的構(gòu)造方法,積累和鞏固知識的同時希望也能幫助到大家,另外有什么不對的地方歡迎大家指正??。
Swift中構(gòu)造方法分類:
- Designated構(gòu)造方法
- Convenience構(gòu)造方法
1、Designated構(gòu)造方法
又稱指定構(gòu)造方法,此方法init前不需要加關(guān)鍵字,是類中的主要構(gòu)造器。它會將類中所有的屬性賦值初始化,并且一路往上調(diào)用類的父類的指定構(gòu)造方法去初始化它們各自引入的屬性。每個類都必須至少有一個designated構(gòu)造方法,但是有些情況你會看到類中沒有聲明designated構(gòu)造方法,那是因為如果是一個子類,不寫任designated構(gòu)造方法,將會自動繼承父類所有designated構(gòu)造方法。另外,不寫任何designated構(gòu)造方法,系統(tǒng)其實也會默認生成一個構(gòu)造方法 init() {} 。
例:
//指定構(gòu)造方法
init (param:String) {
... //此處為了直觀看我用...表示省略
}
2、Convenience構(gòu)造方法
又稱便利構(gòu)造方法,此方法init前需要加convenience關(guān)鍵字,是類中的次要構(gòu)造器。它必須調(diào)用同一個類中的指定構(gòu)造方法或其他的便利構(gòu)造方法(最后還是調(diào)用指定構(gòu)造方法)。每個類可以不需要,也可以定義多個。
例:
//便利構(gòu)造方法
convenience init (param:String) {
self.init(...)
...
}
Swift中構(gòu)造方法遵循規(guī)則:
官方文檔中有如下描述:
子類designated構(gòu)造方法中必須調(diào)用父類的designated構(gòu)造方法。
convenience構(gòu)造方法中必須調(diào)用當(dāng)前類的構(gòu)造方法。
convenience構(gòu)造方法歸根結(jié)底要調(diào)用到designated構(gòu)造方法。

例:
//子類
//自定義指定構(gòu)造方法
init (paramA:String) {
super.init()//需要調(diào)用父類的構(gòu)造方法
}
//自定義便利構(gòu)造方法
convenience init(paramB:String,paramC:String) {
self.init(paramA:"lala")//調(diào)用自己的指定構(gòu)造方法
}
//自定義便利構(gòu)造方法
convenience init(paramD:String) {
self.init(paramB:"lalala",paramC:"llalalal")//也可以調(diào)用自己的便利構(gòu)造方法(最后還是調(diào)用指定構(gòu)造方法)
}
Swift中重寫構(gòu)造方法:
- 重寫父類的designated構(gòu)造方法,方法名前需要加override ,然后調(diào)用父類的(super.)designated構(gòu)造方法。
- 重寫父類的convenience構(gòu)造方法,方法名前不需要加override,一種情況不加convenice關(guān)鍵字,需調(diào)用父類的(super.)designated構(gòu)造方法,另外一種情況加convenice關(guān)鍵字,則必須調(diào)用自己的(self.)構(gòu)造方法。
- 父類中若帶有required關(guān)鍵字的構(gòu)造方法,子類只要有重寫或調(diào)用父類(super.)的designated構(gòu)造方法的,都需要對父類加有required關(guān)鍵字的方法也重寫實現(xiàn)(required關(guān)鍵字,強制子類實現(xiàn)某些構(gòu)造方法)
(注:convenience構(gòu)造方法是不能從子類中以 super 的方式被調(diào)用的)
Swift中構(gòu)造方法繼承的條件:
在 Swift 中,子類默認不會繼承父類的構(gòu)造方法,然而,如果某種條件滿足的話,父類的構(gòu)造方法還是可以繼承給子類。在通常情況下,這意味著你不必復(fù)寫父類的構(gòu)造方法,在安全的前提下可以以最低的代價繼承父類的構(gòu)造方法。
假設(shè)子類新增的屬性都提供了默認值,那么提供了以下兩條規(guī)則:
-
規(guī)則1:
如果你的子類沒有定義任何的指定構(gòu)造方法(新增便利構(gòu)造方法可有可無),那么子類會自動繼承父類的所有指定構(gòu)造方法。 -
規(guī)則2:
如果子類通過規(guī)則1,或者通過自定義實現(xiàn)父類的所有指定構(gòu)造方法,那么子類自動繼承父類的所有便利構(gòu)造方法。(子類以便利構(gòu)造方法覆蓋父類的指定構(gòu)造方法也視為對父類的指定構(gòu)造方法的實現(xiàn)。)
Swift中初始化的過程:
在 Swift 中,類的初始化需要經(jīng)歷兩個步驟,第一個步驟中,每一個該類引入的儲存屬性都需要給賦上一個初始值。完成后,執(zhí)行第二個步驟,每個類都可以再對屬性進行自定義修改。
- 步驟1:
- 一個類的指定或便利初始化器需被調(diào)用
- 類的實例的內(nèi)存被申請,但還沒有初始化
- 指定初始化器確保當(dāng)前類引入的所有成員屬性都初始化,變量沒給賦值默認nil,常量若沒給賦值,須先賦值,注意要在該指定構(gòu)造器方法調(diào)用父類構(gòu)造(super.init(...))方法前賦值。( 另注意:父類的成員屬性也會被子類繼承,如果要在子類復(fù)寫的父類方法中對繼承來的父類成員屬性進行重新構(gòu)造或賦值,則必須在調(diào)用父類構(gòu)造方法之后。步驟2的環(huán)節(jié)了)
- 指定初始化器調(diào)用其父類的指定初始化器,繼續(xù)讓父類去初始化它所引入的成員屬性
- 上面這個過程一直進行直到最終的根類的指定初始化器被調(diào)用
- 當(dāng)根類的指定初始化器調(diào)用后,該類的實例就已經(jīng)確保了所有成員性都已經(jīng)初始化完成,步驟一完成。
- 步驟2:
- 步驟二是從根類的指定初始化器開始一直向下,一層層到最終的子類的指定初始化器
- 在這個步驟中,每個類都有機會對已經(jīng)步驟一中初始化完成的實例再次進行自定義修改。此時初始化器已經(jīng)可以訪問 self,修改屬性或者調(diào)用實例方法了。
(注:遍歷構(gòu)造方法必須在調(diào)用同一個類中的指定構(gòu)造方法或其他的便利構(gòu)造方法(最后還是調(diào)用指定構(gòu)造方法),然后再為屬性賦值)
例:
class FatherClass {
//父類的屬性
var descF = "FatherClass"
let ageF: Int
init(age: Int) {
ageF = age
}
}
class ChildClass: FatherClass {
//子類的屬性
var descC = "ChildClass"
let ageC: Int
let sexC: String
override init(age: Int) {
//調(diào)用父類構(gòu)造方法前進行自己屬性的初始化賦值
sexC = "男"
ageC = age //在指定 init 里我們可以對 let 的實例常量進行賦值,這是初始化方法的重要特點。正常情況下 let 聲明的值是不可變的,無法被賦值,這對構(gòu)建線程安全的 API十分有用。而 init 只可能被調(diào)用一次,所以在 init 里我們可以為不變量進行賦值,而不會引起任何線程安全的問題
super.init(age: age + 30)
//在調(diào)用父類構(gòu)造方法之后,可以對從父類繼承來的變量屬性進行重構(gòu)造
descF = "ChildClassAndFatherClass"
}
//自定義遍歷構(gòu)造方法
convenience init(name:String,age:Int) {
self.init(age:5)
//調(diào)用自己的指定構(gòu)造方法后才可為屬性賦值
descC = "啦啦啦啦"
descF = "lallal"
}
}