兩段式構造過程
Swift 中類的構造過程包含兩個階段。第一個階段,每個存儲型屬性被引入它們的類指定一個初始值。當每個存儲型屬性的初始值被確定后,第二階段開始,它給每個類一次機會,在新實例準備使用之前進一步定制它們的存儲型屬性。
兩段式構造過程的使用讓構造過程更安全,同時在整個類層級結構中給予了每個類完全的靈活性。兩段式構造過程可以防止屬性值在初始化之前被訪問,也可以防止屬性被另外一個構造器意外地賦予不同的值。
注意
Swift 的兩段式構造過程跟 Objective-C 中的構造過程類似。最主要的區別在于階段 1,Objective-C 給每一個屬性賦值0或空值(比如說0或nil)。Swift 的構造流程則更加靈活,它允許你設置定制的初始值,并自如應對某些屬性不能以0或nil作為合法默認值的情況。
Swift 編譯器將執行 4 種有效的安全檢查,以確保兩段式構造過程能不出錯地完成:
安全檢查 1
指定構造器必須保證它所在類引入的所有屬性都必須先初始化完成,之后才能將其它構造任務向上代理給父類中的構造器。
如上所述,一個對象的內存只有在其所有存儲型屬性確定之后才能完全初始化。為了滿足這一規則,指定構造器必須保證它所在類引入的屬性在它往上代理之前先完成初始化。
安全檢查 2
指定構造器必須先向上代理調用父類構造器,然后再為繼承的屬性設置新值。如果沒這么做,指定構造器賦予的新值將被父類中的構造器所覆蓋。
安全檢查 3
便利構造器必須先代理調用同一類中的其它構造器,然后再為任意屬性賦新值。如果沒這么做,便利構造器賦予的新值將被同一類中其它指定構造器所覆蓋。
安全檢查 4
構造器在第一階段構造完成之前,不能調用任何實例方法,不能讀取任何實例屬性的值,不能引用self作為一個值。
類實例在第一階段結束以前并不是完全有效的。只有第一階段完成后,該實例才會成為有效實例,才能訪問屬性和調用方法。
以下是兩段式構造過程中基于上述安全檢查的構造流程展示:
階段 1
某個指定構造器或便利構造器被調用。
完成新實例內存的分配,但此時內存還沒有被初始化。
指定構造器確保其所在類引入的所有存儲型屬性都已賦初值。存儲型屬性所屬的內存完成初始化。
指定構造器將調用父類的構造器,完成父類屬性的初始化。
這個調用父類構造器的過程沿著構造器鏈一直往上執行,直到到達構造器鏈的最頂部。
當到達了構造器鏈最頂部,且已確保所有實例包含的存儲型屬性都已經賦值,這個實例的內存被認為已經完全初始化。此時階段 1 完成。
階段 2
從頂部構造器鏈一直往下,每個構造器鏈中類的指定構造器都有機會進一步定制實例。構造器此時可以訪問self、修改它的屬性并調用實例方法等等。
最終,任意構造器鏈中的便利構造器可以有機會定制實例和使用self。