初始化
目的是確保第一次使用之前某類(lèi)型的新實(shí)例能夠正確初始化
為存儲(chǔ)屬性設(shè)置初始化值
類(lèi)或者結(jié)構(gòu)體實(shí)例化時(shí)必須為所有的存儲(chǔ)屬性設(shè)置一個(gè)合適的初始值??梢栽诔跏蓟骼餅榇鎯?chǔ)屬性設(shè)置一個(gè)初始值,也可以通過(guò)分配一個(gè)默認(rèn)的屬性值作為屬性定義的一部分
當(dāng)給一個(gè)存儲(chǔ)屬性分配默認(rèn)值或者在初始化器里設(shè)置它的值時(shí),不會(huì)調(diào)用任何屬性監(jiān)視器
初始化器
默認(rèn)的屬性值
可以指定默認(rèn)屬性值作為屬性聲明的一部分。
如果一個(gè)屬性一直保持相同的初始值,推薦使用默認(rèn)值而不是在初始化器里設(shè)置它
自定義初始化
初始化形式參數(shù)
與函數(shù)形式參數(shù)語(yǔ)法相同
形式參數(shù)名和實(shí)際參數(shù)標(biāo)簽
與函數(shù)一樣,但是由于初始化器的函數(shù)名是固定的,所以為了能夠區(qū)分,在沒(méi)有提供外部名的情況下Swift自動(dòng)為每一個(gè)形式參數(shù)提供一個(gè)外部名稱
無(wú)實(shí)際參數(shù)標(biāo)簽的初始化器形式參數(shù)
如果不想為初始化器形式參數(shù)使用實(shí)際參數(shù)標(biāo)簽,可以寫(xiě)一個(gè)下劃線替代明確的實(shí)際參數(shù)標(biāo)簽以重寫(xiě)默認(rèn)行為
可選屬性類(lèi)型
可選屬性在初始化時(shí)可以不提供值,自動(dòng)初始化為nil
在初始化中分配常量屬性
初始化的任意時(shí)刻,都可以給常量屬性賦值
對(duì)于類(lèi)實(shí)例,常量屬性在初始化中只能通過(guò)引用的類(lèi)修改,不能在子類(lèi)中被修改
默認(rèn)初始化器
如果沒(méi)有定義初始化器,Swift提供一個(gè)默認(rèn)初始化器,為所有的屬性提供默認(rèn)值
只有在給每個(gè)屬性提供默認(rèn)值的時(shí)候才能提供默認(rèn)初始化器,否則無(wú)法生成默認(rèn)初始化器
結(jié)構(gòu)體類(lèi)型的成員初始化器
如果結(jié)構(gòu)體類(lèi)型中沒(méi)有定義任何初始化器,它會(huì)自動(dòng)獲得一個(gè)成員初始化器。不同于默認(rèn)初始化器,結(jié)構(gòu)體會(huì)接收成員初始化器即使它的屬性沒(méi)有默認(rèn)值
值類(lèi)型的初始化器委托
初始化器可以調(diào)用其他初始化器來(lái)執(zhí)行部分實(shí)例的初始化。這個(gè)過(guò)程,就是所謂的初始化器委托,避免了多個(gè)初始化器里冗余代碼。
初始化器委托的運(yùn)作,以及允許哪些形式的委托,這些規(guī)則對(duì)于值類(lèi)型和類(lèi)類(lèi)型是不同的。原因在于值類(lèi)型不支持繼承,所以簡(jiǎn)單一些
如果你為值類(lèi)型定義了自定義初始化器,那么就不能訪問(wèn)那個(gè)類(lèi)型的默認(rèn)初始化器。這個(gè)限制防止別人意外的使用自動(dòng)初始化器而把復(fù)雜初始化器里提供的額外必要配置給覆蓋掉的情況發(fā)生。
如果想要自定義值類(lèi)型能夠使用默認(rèn)初始化器和成員初始化器初始化,以及自定義初始化器來(lái)初始化,把自定義初始化器寫(xiě)在擴(kuò)展里而不是作為值類(lèi)型原始定義的一部分可以實(shí)現(xiàn)。
類(lèi)的繼承和初始化
所有類(lèi)的存儲(chǔ)屬性,包括繼承而來(lái)的,都必須在初始化期間分配初始值
指定初始化器和便捷初始化器
指定初始化器是類(lèi)的主要初始化器。指定初始化器可以初始化所有那個(gè)類(lèi)引用的屬性并且調(diào)用合適的父類(lèi)初始化器來(lái)繼續(xù)這個(gè)初始化過(guò)程給父類(lèi)鏈。
類(lèi)偏向于少量指定初始化器,但至少得有一個(gè)。在某些情況下,這些需求可以通過(guò)從父類(lèi)繼承一個(gè)或者多個(gè)指定初始化器來(lái)滿足。
便捷初始化器是次要的??梢圆惶峁?。
指定初始化器和便捷初始化器語(yǔ)法
convenience
指定初始化器不需要修飾
類(lèi)類(lèi)型的初始化器委托
為了簡(jiǎn)化指定和便捷初始化器之間的調(diào)用關(guān)系,Swift指定三個(gè)規(guī)則
- 指定初始化器必須從他的直系父類(lèi)調(diào)用指定初始化器(繼承來(lái)的也算)
- 便捷初始化器必須從相同的類(lèi)里調(diào)用另一個(gè)初始化器
- 便捷初始化器最終必須調(diào)用一個(gè)指定初始化器
簡(jiǎn)單講,指定初始化器總是向上委托,便利初始化器從事橫向委托
兩段式初始化
在第一個(gè)階段,每一個(gè)存儲(chǔ)屬性被引入類(lèi)時(shí)分配了一個(gè)初始值,一旦每個(gè)存儲(chǔ)屬性的初始狀態(tài)被確定,第二個(gè)階段就開(kāi)始了,每個(gè)類(lèi)都有機(jī)會(huì)在新的實(shí)例準(zhǔn)備使用之前來(lái)定制它的存儲(chǔ)屬性
Swift編譯器執(zhí)行四種有效的安全檢查來(lái)確保兩段式初始化過(guò)程能夠順利完成:
- 指定初始化器必須保證在向上委托給父類(lèi)初始化器之前,其所在類(lèi)引入的所有屬性都要初始化完成
- 指定初始化器必須先向上委托父類(lèi)初始化器,然后才能為繼承的屬性設(shè)置新值。如果不這樣做,指定初始化器賦予的新值將被父類(lèi)中的初始化器所覆蓋
- 便捷初始化器必須先委托同類(lèi)中的其它初始化器,然后再為任意屬性賦新值(包括同類(lèi)里定義的屬性)。如果沒(méi)這么做,便捷初始化器賦予的新值將被自己類(lèi)中其它指定初始化器所覆蓋
- 初始化器在第一階段初始化完成之前,不能調(diào)用任何實(shí)例方法、不能讀取任何實(shí)例屬性的值,也不能引用self作為值
兩段初始化過(guò)程:
階段1
- 指定或便捷初始化器在類(lèi)中被調(diào)用
- 為這個(gè)類(lèi)的新實(shí)例分配內(nèi)存。內(nèi)存還沒(méi)有被初始化
- 這個(gè)類(lèi)的指定初始化器確保所有由此類(lèi)引入的存儲(chǔ)屬性都有一個(gè)值?,F(xiàn)在這些存儲(chǔ)屬性的內(nèi)存被初始化了
- 指定初始化器上交父類(lèi)的初始化器為其存儲(chǔ)屬性執(zhí)行相同的任務(wù)
- 這個(gè)調(diào)用父類(lèi)初始化器的過(guò)程將沿著初始化器鏈一直向上進(jìn)行,直到到達(dá)初始化器鏈的最頂部
- 一旦到達(dá)了初始化器的最頂部,在鏈頂部的類(lèi)確保左右的存儲(chǔ)屬性都有一個(gè)值,此實(shí)例的內(nèi)存被認(rèn)為完全初始化了,此時(shí)第一階段完成
階段2
- 從頂部初始化器往下,鏈中的每一個(gè)指定初始化器都有機(jī)會(huì)進(jìn)一步定制實(shí)例。初始化器現(xiàn)在能夠訪問(wèn)self并且可以修改它的屬性,調(diào)用它的實(shí)例方法等等
- 最終,鏈中任何便捷初始化器都有機(jī)會(huì)定制實(shí)例以及使用self
初始化器的繼承和重寫(xiě)
Swift的子類(lèi)不會(huì)默認(rèn)繼承父類(lèi)的初始化器。這種機(jī)制防止父類(lèi)的簡(jiǎn)單初始化器被一個(gè)更專(zhuān)用的子類(lèi)繼承并被用來(lái)創(chuàng)建一個(gè)沒(méi)有完全或錯(cuò)誤初始化的新實(shí)例的情況發(fā)生。
如果重寫(xiě)了一個(gè)匹配父類(lèi)便捷初始化器的子類(lèi)初始化器,父類(lèi)的便捷初始化器將永遠(yuǎn)不會(huì)通過(guò)你的子類(lèi)直接調(diào)用。因此,子類(lèi)(嚴(yán)格意義上來(lái)講)不能提供父類(lèi)便捷初始化器的重寫(xiě)。當(dāng)提供一個(gè)匹配父類(lèi)便捷初始化器的實(shí)現(xiàn)時(shí),不用寫(xiě)override
自動(dòng)初始化器的繼承
子類(lèi)默認(rèn)不會(huì)繼承父類(lèi)初始化器,但有例外
如果子類(lèi)引入的任何新屬性都提供了默認(rèn)值,則
- 子類(lèi)沒(méi)有定義任何指定初始化器,會(huì)自動(dòng)繼承父類(lèi)所有的指定初始化器
- 子類(lèi)提供了所有父類(lèi)指定初始化器的實(shí)現(xiàn):要么通過(guò)1中繼承而來(lái),要么全部自定義。它自動(dòng)繼承所有的父類(lèi)便捷初始化器
指定和便利初始化器的操作
可失敗初始化器
不能定義可失敗初始化器和非可失敗初始化器為相同的形式參數(shù)類(lèi)型和名稱
可失敗初始化器通過(guò)返回nil表明失敗
枚舉的可失敗初始化器
帶有原始值枚舉的可失敗初始化器
初始化失敗的傳遞
重寫(xiě)可失敗初始化器
可以重寫(xiě)父類(lèi)的可失敗初始化器,也可用子類(lèi)的非可失敗初始化器來(lái)重寫(xiě)父類(lèi)可失敗初始化器
可失敗初始化器init!
必要初始化器
required
子類(lèi)必須實(shí)現(xiàn)
通過(guò)閉包和函數(shù)來(lái)設(shè)置屬性的默認(rèn)值
可以使用閉包或者全局函數(shù)來(lái)為屬性提供默認(rèn)值,當(dāng)這個(gè)屬性初始化時(shí),閉包或者函數(shù)就會(huì)被調(diào)用
class SomeClass {
let someProperty: SomeType = {
// create a default value for someProperty inside this closure
// someValue must be of the same type as SomeType
return someValue
}()
}
反初始化
反初始化器原理
反初始化器deinit后面不需要寫(xiě)圓括號(hào)
子類(lèi)的反初始化器調(diào)用結(jié)束之后父類(lèi)的反初始化器會(huì)被調(diào)用