類里面的所有存儲(chǔ)型屬性--包括所有繼承自父類的屬性--都必須在構(gòu)造過(guò)程中設(shè)置初始值。
Swift 提供了兩種類型的類構(gòu)造器來(lái)確保所有類實(shí)例中存儲(chǔ)型屬性都能獲得初始值,它們分別是指定構(gòu)造器和便利構(gòu)造器。
指定構(gòu)造器是類中最主要的構(gòu)造器。一個(gè)指定構(gòu)造器將初始化類中提供的所有屬性,并根據(jù)父類鏈往上調(diào)用父類的構(gòu)造器來(lái)實(shí)現(xiàn)父類的初始化。
每一個(gè)類都必須擁有至少一個(gè)指定構(gòu)造器。在某些情況下,許多類通過(guò)繼承了父類中的指定構(gòu)造器而滿足了這個(gè)條件。具體內(nèi)容請(qǐng)參考后續(xù)章節(jié)自動(dòng)構(gòu)造器的繼承。
便利構(gòu)造器是類中比較次要的、輔助型的構(gòu)造器。你可以定義便利構(gòu)造器來(lái)調(diào)用同一個(gè)類中的指定構(gòu)造器,并為其參數(shù)提供默認(rèn)值。你也可以定義便利構(gòu)造器來(lái)創(chuàng)建一個(gè)特殊用途或特定輸入的實(shí)例。
你應(yīng)當(dāng)只在必要的時(shí)候?yàn)轭愄峁┍憷麡?gòu)造器,比方說(shuō)某種情況下通過(guò)使用便利構(gòu)造器來(lái)快捷調(diào)用某個(gè)指定構(gòu)造器,能夠節(jié)省更多開(kāi)發(fā)時(shí)間并讓類的構(gòu)造過(guò)程更清、晰明。
為了簡(jiǎn)化指定構(gòu)造器和便利構(gòu)造器之間的調(diào)用關(guān)系,Swift 采用以下三條規(guī)則來(lái)限制構(gòu)造器之間的代理調(diào)用:
指定構(gòu)造器必須調(diào)用其直接父類的的指定構(gòu)造器。
便利構(gòu)造器必須調(diào)用同一類中定義的其它構(gòu)造器。
便利構(gòu)造器必須最終以調(diào)用一個(gè)指定構(gòu)造器結(jié)束。
一個(gè)更方便記憶的方法是:
這些規(guī)則可以通過(guò)下面圖例來(lái)說(shuō)明:

如圖所示,父類中包含一個(gè)指定構(gòu)造器和兩個(gè)便利構(gòu)造器。其中一個(gè)便利構(gòu)造器調(diào)用了另外一個(gè)便利構(gòu)造器,而后者又調(diào)用了唯一的指定構(gòu)造器。這滿足了上面提到的規(guī)則2和3。這個(gè)父類沒(méi)有自己的父類,所以規(guī)則1沒(méi)有用到。
子類中包含兩個(gè)指定構(gòu)造器和一個(gè)便利構(gòu)造器。便利構(gòu)造器必須調(diào)用兩個(gè)指定構(gòu)造器中的任意一個(gè),因?yàn)樗荒苷{(diào)用同一個(gè)類里的其他構(gòu)造器。這滿足了上面提到的規(guī)則2和3。而兩個(gè)指定構(gòu)造器必須調(diào)用父類中唯一的指定構(gòu)造器,這滿足了規(guī)則1。
注意:
這些規(guī)則不會(huì)影響使用時(shí),如何用類去創(chuàng)建實(shí)例。任何上圖中展示的構(gòu)造器都可以用來(lái)完整創(chuàng)建對(duì)應(yīng)類的實(shí)例。這些規(guī)則只在實(shí)現(xiàn)類的定義時(shí)有影響。
下面圖例中展示了一種更復(fù)雜的類層級(jí)結(jié)構(gòu)。它演示了指定構(gòu)造器是如果在類層級(jí)中充當(dāng)“管道”的作用,在類的構(gòu)造器鏈上簡(jiǎn)化了類之間的內(nèi)部關(guān)系。

Swift 中類的構(gòu)造過(guò)程包含兩個(gè)階段。第一個(gè)階段,每個(gè)存儲(chǔ)型屬性通過(guò)引入它們的類的構(gòu)造器來(lái)設(shè)置初始值。當(dāng)每一個(gè)存儲(chǔ)型屬性值被確定后,第二階段開(kāi)始,它給每個(gè)類一次機(jī)會(huì)在新實(shí)例準(zhǔn)備使用之前進(jìn)一步定制它們的存儲(chǔ)型屬性。
兩段式構(gòu)造過(guò)程的使用讓構(gòu)造過(guò)程更安全,同時(shí)在整個(gè)類層級(jí)結(jié)構(gòu)中給予了每個(gè)類完全的靈活性。兩段式構(gòu)造過(guò)程可以防止屬性值在初始化之前被訪問(wèn);也可以防止屬性被另外一個(gè)構(gòu)造器意外地賦予不同的值。
注意:
Swift的兩段式構(gòu)造過(guò)程跟 Objective-C 中的構(gòu)造過(guò)程類似。最主要的區(qū)別在于階段 1,Objective-C 給每一個(gè)屬性賦值0或空值(比如說(shuō)0或nil)。Swift 的構(gòu)造流程則更加靈活,它允許你設(shè)置定制的初始值,并自如應(yīng)對(duì)某些屬性不能以0或nil作為合法默認(rèn)值的情況。
Swift 編譯器將執(zhí)行 4 種有效的安全檢查,以確保兩段式構(gòu)造過(guò)程能順利完成:
指定構(gòu)造器必須保證它所在類引入的所有屬性都必須先初始化完成,之后才能將其它構(gòu)造任務(wù)向上代理給父類中的構(gòu)造器。
如上所述,一個(gè)對(duì)象的內(nèi)存只有在其所有存儲(chǔ)型屬性確定之后才能完全初始化。為了滿足這一規(guī)則,指定構(gòu)造器必須保證它所在類引入的屬性在它往上代理之前先完成初始化。
指定構(gòu)造器必須先向上代理調(diào)用父類構(gòu)造器,然后再為繼承的屬性設(shè)置新值。如果沒(méi)這么做,指定構(gòu)造器賦予的新值將被父類中的構(gòu)造器所覆蓋。
便利構(gòu)造器必須先代理調(diào)用同一類中的其它構(gòu)造器,然后再為任意屬性賦新值。如果沒(méi)這么做,便利構(gòu)造器賦予的新值將被同一類中其它指定構(gòu)造器所覆蓋。
構(gòu)造器在第一階段構(gòu)造完成之前,不能調(diào)用任何實(shí)例方法、不能讀取任何實(shí)例屬性的值,也不能引用self的值。
以下是兩段式構(gòu)造過(guò)程中基于上述安全檢查的構(gòu)造流程展示:
self、修改它的屬性并調(diào)用實(shí)例方法等等。self。
下圖展示了在假定的子類和父類之間構(gòu)造的階段1: ·
在這個(gè)例子中,構(gòu)造過(guò)程從對(duì)子類中一個(gè)便利構(gòu)造器的調(diào)用開(kāi)始。這個(gè)便利構(gòu)造器此時(shí)沒(méi)法修改任何屬性,它把構(gòu)造任務(wù)代理給同一類中的指定構(gòu)造器。
如安全檢查1所示,指定構(gòu)造器將確保所有子類的屬性都有值。然后它將調(diào)用父類的指定構(gòu)造器,并沿著造器鏈一直往上完成父類的構(gòu)建過(guò)程。
父類中的指定構(gòu)造器確保所有父類的屬性都有值。由于沒(méi)有更多的父類需要構(gòu)建,也就無(wú)需繼續(xù)向上做構(gòu)建代理。
一旦父類中所有屬性都有了初始值,實(shí)例的內(nèi)存被認(rèn)為是完全初始化,而階段1也已完成。
以下展示了相同構(gòu)造過(guò)程的階段2:

父類中的指定構(gòu)造器現(xiàn)在有機(jī)會(huì)進(jìn)一步來(lái)定制實(shí)例(盡管它沒(méi)有這種必要)。
一旦父類中的指定構(gòu)造器完成調(diào)用,子類的構(gòu)指定構(gòu)造器可以執(zhí)行更多的定制操作(同樣,它也沒(méi)有這種必要)。
最終,一旦子類的指定構(gòu)造器完成調(diào)用,最開(kāi)始被調(diào)用的便利構(gòu)造器可以執(zhí)行更多的定制操作。
跟 Objective-C 中的子類不同,Swift 中的子類不會(huì)默認(rèn)繼承父類的構(gòu)造器。Swift 的這種機(jī)制可以防止一個(gè)父類的簡(jiǎn)單構(gòu)造器被一個(gè)更專業(yè)的子類繼承,并被錯(cuò)誤的用來(lái)創(chuàng)建子類的實(shí)例。
假如你希望自定義的子類中能實(shí)現(xiàn)一個(gè)或多個(gè)跟父類相同的構(gòu)造器--也許是為了完成一些定制的構(gòu)造過(guò)程--你可以在你定制的子類中提供和重載與父類相同的構(gòu)造器。
如果你重載的構(gòu)造器是一個(gè)指定構(gòu)造器,你可以在子類里重載它的實(shí)現(xiàn),并在自定義版本的構(gòu)造器中調(diào)用父類版本的構(gòu)造器。
如果你重載的構(gòu)造器是一個(gè)便利構(gòu)造器,你的重載過(guò)程必須通過(guò)調(diào)用同一類中提供的其它指定構(gòu)造器來(lái)實(shí)現(xiàn)。這一規(guī)則的詳細(xì)內(nèi)容請(qǐng)參考構(gòu)造器鏈。
注意:
與方法、屬性和下標(biāo)不同,在重載構(gòu)造器時(shí)你沒(méi)有必要使用關(guān)鍵字上一篇:Swift檢驗(yàn)協(xié)議的一致性下一篇:Swift斷言