Swift中初始化器:
- 指定初始化器(designated initializer)
- 便捷初始化器(convenience initializer)
初始化器定義
// 指定初始化器
init(parameters) {
statements
}
// 便捷初始化器
convenience init(parameters) {
statements
}
通常每個(gè)類的初始化器有如下特點(diǎn)
1.每個(gè)類至少有一個(gè)指定初始化器淤刃,指定初始化器是類的主要初始化器
2.默認(rèn)初始化器總是類的指定初始化器
3.類偏向于指定初始化器讯壶,一個(gè)類通常只有一個(gè)指定的初始化器
關(guān)于指定初始化器和便利初始化器關(guān)系荠雕,有以下三個(gè)原則
1.指定初始化器必須調(diào)用它的直接直系父類指定初始化器
2.便捷初始化器必須調(diào)用本類的另一個(gè)初始化器(可以使便利或指定)
3.編輯初始化器“最終”必須調(diào)用一個(gè)指定初始化器(這里的最終是指調(diào)用鏈的尾端必須調(diào)用指定初始化器)
一、初始化器的調(diào)用規(guī)則
- 指定初始化器:縱向調(diào)用
- 便利初始化器:橫向調(diào)用
縱向調(diào)用:指子類指定初始化器調(diào)用父類指定初始化器(指定初始化器之間不能相互調(diào)用)
橫向調(diào)用:指本類內(nèi)部相互調(diào)用(便利初始化器可以調(diào)用便利和指定初始化器)
第一階段:初始化所有存儲屬性
1.外層調(diào)用指定狐赡、便捷初始化器
2.分配內(nèi)存給實(shí)例(有了存儲空間唯竹,但未初始化沸停,空間內(nèi)是垃圾數(shù)據(jù))
3.指定初始化器確保當(dāng)前類的存儲屬性都被初始化
4.指定初始化器調(diào)用父類的初始化器辆影,不斷向上,形成初始化器鏈
第二階段:設(shè)置新的存儲屬性
1.從頂部初始化器向下后添,鏈中的每一個(gè)指定初始化器都有機(jī)會進(jìn)一步定制實(shí)例
2.此時(shí)初始化器能夠使用self(訪問笨枯、修改屬性,調(diào)用實(shí)例方法等等)
3.最終遇西,鏈中任何便捷初始化器都有機(jī)會定制實(shí)例以及使用self
二馅精、初始化器的調(diào)用規(guī)則
- 1.指定初始化器之間不能相互調(diào)動
一個(gè)指定初始化器意味著一條特定的業(yè)務(wù)場景線,所以相互之間不能調(diào)用
如下一個(gè)類粱檀,有兩個(gè)指定初始化器init(age: Int, name: String)
和init(age: Int)
,這兩個(gè)初始化器之間是不能調(diào)用的洲敢,因?yàn)槌跏蓟螽a(chǎn)生的業(yè)務(wù)場景并不同
class Object {
var age = 10
var name = "Rose"
init(age: Int, name: String) {
self.age = age
self.name = name
}
init(age: Int) {
self.age = age
self.name = "Jack"
}
}
2.便利初始化器可以調(diào)用指定初始化器,也可以調(diào)用便利初始器(此情況最終傳遞到指定初始化器)
如下初始化器的傳遞情況init()
-->init(age: Int)
-->init(age: Int, name: String)
,雖然前兩個(gè)初始化器都是便利初始化器梧税,但最終落腳點(diǎn)是指定初始化器
class Object {
var age = 10
var name = "Rose"
init(age: Int, name: String) {
self.age = age
self.name = name
}
convenience init(age: Int) {
self.init(age: 10, name: "Jack")
}
convenience init() {
self.init(age: 10)
}
}
三沦疾、初始化器繼承
- 當(dāng)子類不寫任何初始化器的時(shí)候,默認(rèn)繼承父類所有初始化器
- 當(dāng)子類不寫任何指定初始化器的時(shí)候第队,默認(rèn)繼承父類所有初始化器
class Object {
var age = 10
var name = "Rose"
init(age: Int, name: String) {
self.age = age
self.name = name
}
convenience init(age: Int) {
self.init(age: 10, name: "Jack")
}
convenience init() {
self.init(age: 10)
}
}
class Person: Object {
var sex = true
convenience init(sex: Bool) {
self.init()
self.sex = sex
}
convenience init(sex: Bool, name: String) {
self.init(age: 20)
self.sex = sex
}
}
這里的Person
實(shí)際上已經(jīng)默認(rèn)繼承了Object的所有初始化器哮塞,這里Person
擁有5個(gè)初始化器
- 當(dāng)子類有自定義初始化器的時(shí)候,不會繼承父類初始化器(包括指定和便利)
class Object {
var age = 10
var name = "Rose"
init(age: Int, name: String) {
self.age = age
self.name = name
}
convenience init(age: Int) {
self.init(age: 10, name: "Jack")
}
convenience init() {
self.init(age: 10)
}
}
class Person: Object {
var sex = true
init() {
super.init(age: 20, name: "sss")
}
convenience init(sex: Bool) {
self.init()
self.sex = sex
}
}
這里的Person
沒有繼承Object的所有初始化器凳谦,Person
只有本身的2個(gè)初始化器
- 當(dāng)子類沒有新的指定初始化器忆畅,但是重寫了父類的指定初始化器的時(shí)候,此時(shí)父類的所有初始化構(gòu)造器都會被繼承下來
便捷初始化器不能重寫尸执,也就是子類不能夠重寫家凯,嚴(yán)格意義上來說不能算繼承
class Object {
var age = 10
var name = "Rose"
init(age: Int, name: String) {
self.age = age
self.name = name
}
convenience init(age: Int) {
self.init(age: 10, name: "Jack")
}
convenience init() {
self.init(age: 10)
}
}
class Person: Object {
var sex: Bool
override init(age: Int, name: String) {
sex = false
super.init(age: age, name: name)
}
}
這里的Person
繼承了Object的所有初始化器,這里Person
擁有3個(gè)初始化器
三如失、兩段式初始化
所有分段式初始化绊诲,即一個(gè)初始化函數(shù)的內(nèi)部初始化過程分為兩段(三個(gè)步驟)
- 初始化自己所有存儲屬性
- 調(diào)用父類初始化方法super.init()
- 個(gè)性化定制(為成員變量重新賦值、調(diào)用成員方法等)
init(sex: Bool, id: String) {
// 1. 初始化自己所有存儲屬性
self.sex = sex
self.id = id
// 調(diào)用父類初始化方法
super.init(age: 10, name: "Jack")
// 3. 個(gè)性化定制
self.age = 20
self.name = "Jack1"
self.test()
}
swift為了安全性更上一個(gè)等級褪贵,設(shè)計(jì)了這樣一個(gè)兩段式結(jié)構(gòu)掂之,過程體現(xiàn)如下
初始化屬性:子類-->父類-->...-->基類
個(gè)性化定制:基類-->...-->父類-->子類
原理上來說,運(yùn)用了棧的結(jié)構(gòu)思想脆丁,保證了:
1.所有繼承鏈上的成員變量能夠被初始化到
2.指定初始化器形成調(diào)用鏈
3.個(gè)性化定制一定在類完全初始化之后
四世舰、安全檢查
- 指定初始化器必須在保證調(diào)用父類初始化器之前,必須保證本類所有存儲屬性都要初始化完成
- 指定初始化器必須在調(diào)用父類初始化器之后槽卫,才能為繼承的屬性設(shè)置新值
- 便捷初始化器必須先調(diào)用同類中國的其它指定初始化器之后跟压,才能為任意屬性設(shè)置新值
- 初始化器在1階段完成之前不能訪問self、屬性即調(diào)用實(shí)例方法
- 直到階段1結(jié)束歼培,才能算初始化過程合法
五震蒋、重寫
- 當(dāng)重寫父類的指定初始化器時(shí)茸塞,必須加上override(即使子類的實(shí)現(xiàn)是便捷初始化器)
- 如果子類寫了一個(gè)匹配父類便捷初始化器的初始化器,不用加上override因?yàn)楦割惖谋憬莩跏蓟饔肋h(yuǎn)不會通過子類直接調(diào)用喷好,因此翔横,嚴(yán)格來說读跷,子類無法重寫父類的便捷初始化器
六梗搅、自動繼承
- 1.如果子類沒有定義任何指定初始化器,它會自動繼承父類所有的指定初始化器
- 2.如果子類提供了父類所有指定初始化器的實(shí)現(xiàn)(要么通過方式1繼承效览,要么重寫)无切,那么子類自動繼承所有的父類便捷初始化器
- 3.就算子類添加了更多的便捷初始化器,這些規(guī)則仍然適用
- 4.子類以便捷初始化器的形式重寫父類的指定初始化器丐枉,也可以作為滿足規(guī)則2的一部分
總結(jié)
- 1.初始化器必須滿足分段規(guī)則
- 2.只要之類沒有自定義新的 指定 初始化器(繼承和重寫得來的不算)哆键,子類擁有父類所有初始化器
- 3.便捷初始化方法內(nèi)部不能使用super調(diào)用父類初始化器,只能使用self調(diào)用本身擁有或繼承得來的