swift初始化器有兩種:
- 指定初始化器(designated initializer)
- 便捷初始化器(convenience initializer)
初始化器的一些特點(diǎn):
- 每個(gè)類(lèi)至少有一個(gè)初始化器
- 自己沒(méi)有添加初始化器的話篡腌,編譯器會(huì)自動(dòng)添加
init(){ }
- 一旦自己實(shí)現(xiàn)了指定初始化器的話,編譯器就不會(huì)自動(dòng)添加
init(){ }
- 自己沒(méi)有添加初始化器的話篡腌,編譯器會(huì)自動(dòng)添加
- 官方建議 類(lèi)使用少量指定初始化器
初始化器的調(diào)用規(guī)則:
- 指定初始化器必須從他的直系父類(lèi)調(diào)用初始化器(安全:保證父類(lèi)的初始化完成)
- 同一個(gè)類(lèi)中勾效,多個(gè)指定初始化器之間不能相互調(diào)用
- 便捷初始化器必須從相同的類(lèi)里調(diào)用另一個(gè)初始化器
- 不能調(diào)用父類(lèi)的初始化器嘹悼,只能橫向調(diào)用
- 多個(gè)便捷初始化器,可以相互調(diào)用
- 便捷初始化器最終必須調(diào)用一個(gè)指定初始化器(這樣做事為了安全层宫,不管使用哪種方式創(chuàng)建杨伙,都必須走初始化代碼)
- 便捷初始化器只能且必須調(diào)用自己的初始化器,不能調(diào)用父類(lèi)的初始化器
下圖是初始化器之間的相互調(diào)用關(guān)系:
這樣保證了萌腿,使用任意初始化器限匣,都可以完整的初始化實(shí)例
兩段式初始化
第一階段:初始化所有成員
- 初始化自己的所有成員變量
- 調(diào)用父類(lèi)的初始化方法,初始化父類(lèi)的成員變量毁菱,如果還有父類(lèi)米死,一層層向上調(diào)用
調(diào)用如下圖:
第二階段
- 對(duì)屬性設(shè)置新值(例如對(duì)父類(lèi)的成員變量賦值)
- 只有第一階段完成锌历,即初始化結(jié)束,才能使用 self 訪問(wèn)峦筒、修改成員變量或者調(diào)用他的實(shí)例方法
這個(gè)調(diào)用是從上到下的如圖:
一個(gè)完整的初始化過(guò)程從上到下:
總結(jié):蘋(píng)果做的安全檢查
- 指定初始化器必須在調(diào)用父類(lèi)初始化之前究西,給自己所有成員變量賦值
- 指定初始化器必須先調(diào)用父類(lèi)的初始化器,然后才能為繼承的屬性賦值
- 便捷初始化器必須先調(diào)用同類(lèi)的其他初始化器物喷,然后再為任意屬性設(shè)值
- 初始化器在第一階段完成之前卤材,不能調(diào)用任何實(shí)例方法,不能讀取任何屬性的值峦失,不能 引用self
override
特點(diǎn)
- 重寫(xiě)父類(lèi)的指定初始化器商膊,添加override
- 子類(lèi)實(shí)現(xiàn)跟父類(lèi)相同的便捷初始化器,不需要添加override宠进,
- 重寫(xiě)的特點(diǎn)就是在子類(lèi)中能否調(diào)用到父類(lèi)的方法晕拆,而子類(lèi)的便捷初始化器是調(diào)用不到父類(lèi)的便捷初始化器的,嚴(yán)格來(lái)說(shuō)材蹬,子類(lèi)無(wú)法重寫(xiě)父類(lèi)的便捷初始化器
自動(dòng)繼承
- 如果子類(lèi)沒(méi)有定義任何指定初始化器实幕,它會(huì)自動(dòng)繼承父類(lèi)所有的初始化器,自己不會(huì)在添加
init(){}
如圖:
- 如果子類(lèi)提供了父類(lèi)所有的初始化器的實(shí)現(xiàn)(要么通過(guò)繼承:上面自動(dòng)繼承的方式堤器,要么重寫(xiě))
- 子類(lèi)自動(dòng)繼承多有的父類(lèi)便捷初始化器
-
即使子類(lèi)以便捷初始化器的形式重寫(xiě)指定初始化器昆庇,同樣滿足上面一條的規(guī)則
如圖:
舉個(gè)反例:
required
- 使用required修飾指定初始化器,其子類(lèi)必須都實(shí)現(xiàn)該初始化器(繼承或者重寫(xiě))
- 子類(lèi)重寫(xiě)了required初始化器闸溃,也必須添加required整吆,但是無(wú)需加override
- 補(bǔ)充一點(diǎn):required只對(duì)指定初始化器有效,便捷初始化器添加上也不會(huì)報(bào)錯(cuò)辉川,只是沒(méi)有用表蝙,原因很簡(jiǎn)單,便捷初始化器是橫向調(diào)用的乓旗,沒(méi)有子類(lèi)繼承父類(lèi)這種
屬性觀察器
這里涉及到一個(gè)屬性觀察器的一個(gè)小知識(shí)點(diǎn):
屬性觀察器在自己的初始化中是不會(huì)被調(diào)用的府蛇,但是在子類(lèi)中的初始化中,是會(huì)被調(diào)用的
class Animal: NSObject {
var name: String {
willSet {
print("willSet: \(newValue)")
}
didSet {
print("didSet: \(oldValue)")
}
}
init(name: String) {
self.name = name
super.init()
}
}
class Person: Animal {
var height: Double
init(height: Double) {
self.height = height
super.init(name: "jack")
self.name = "rose"
}
}
// 沒(méi)有打印
Animal(name: "swift")
/*
打印
willSet: rose
didSet: jack
*/
Person(height: 19)
可失敗初始化器
init?(){ }
允許初始化器為nil屿愚;calss汇跨,結(jié)構(gòu)體,枚舉 都可以定義可失敗初始化器
Int("xxxx")
public init?(_ description: String)
這個(gè)就是可失敗初始化器
deinit
deinit
類(lèi)似于OC中的dealloc妆距,內(nèi)存釋放的時(shí)候調(diào)用
class Aniaml {
deinit {
print("對(duì)象銷(xiāo)毀了")
}
}
父類(lèi)的deinit可以被繼承穷遂;
子類(lèi)的deinit調(diào)用完成后會(huì)在調(diào)用父類(lèi)的deinit