Swift Initialization (2) — Initializer Delegation

Racing Wang
17LIVE Tech Insight
6 min readJul 29, 2020

Swift Initialization (1) — Default Initializer

Swift Initialization (2) — Initializer Delegation

Swift Initialization (3) — Two-Phase Initialization

Delegation 意思是「委派」,所有 iOS 開發者相信對這個詞都不陌生,因為原生物件大量使用 Delegation Pattern(委派模式),甚至只要初創建 App Project 就會自動為你產生一個 AppDelegate。雖然 Initializer Delegation 所指的並不是 Delegation Pattern,但卻隱含著類似的味道:將部分責任委派給其他人來處理。也就是說:

A Initializer 呼叫 B Initializer 的行為稱作 Initializer Delegation

在這種情況下,每個 Initializer 封裝自己的初始化邏輯,除了達到程式碼重用性之外,也將責任定義得更清楚。

Initializer Delegation for Value Types

由於 Value Type(Struct 和 Enum)無法繼承,因此 Delegation 行為相對單純,它們只能委派給自己內部其他的 Initializer。

struct Rect {
let origin: Point
let size: Size
init(origin: Point, size: Size) {
self.origin = origin
self.size = size
}
init(center: Point, size: Size) {
let x = center.x - size.width / 2
let y = center.y - size.height / 2

// Initializer Delegation
self.init(origin: Point(x: x, y: y), size: size)
}
}

透過委派,每個 Initializer 各司其職,init(center:size:) 負責提供不同的介面應對不同的 Use Case,最終仍由 init(origin:size:) 負責 Stored Property 的首次賦值。

Initializer Delegation for Class Types

相較於 Value Type,Class Type 的 Delegation 就複雜許多,在繼承關係底下,為了保持讓少數 Initializer 能夠負責首次賦值,同時又能享有彈性的介面以對付各種 Use Case,Class 引入了兩種 Initializer,也就是 Designated Initializer 以及 Convenience Initializer

Designated Initializer 和 Convenience Initializer 比較圖

Designated Initializer

  1. 主要的 Initializer
  2. Funnel Point(稍後用圖解釋)
  3. 負責完成 Superclass Chain(稍後用圖解釋)
  4. 至少要實作一個 Designated Initializer,其中包含 Default Initializer、自動繼承或覆寫(override)而來(關於自動繼承和覆寫會在之後的文章說明)

Convenience Initializer

  1. 次要的 Initializer
  2. 負責特定 Use Case 的初始化
  3. 接收不同的 Input 以提供彈性的初始化介面
  4. 可選擇性實作

委派規則

  1. Designated Initializer 必須委派給父類別的 Designated Initializer
  2. Convenience Initializer 必須委派給同類別的任一種 Initializer
  3. Convenience Initializer 最終必須委派給同類別的 Designated Initializer

我們用一張圖比較好理解:

若大家認為上述三種規則太難記憶,我們可以將它歸納成:

Designated Initializer 必須向上委派(Delegate Up)

Convenience Initializer 必須橫向委派(Delegate Across)

再來看一個比較複雜的例子:

這張圖很好地解釋了為什麼 Designated Initializer 稱作 Funnel Point,因為它們是向上委派的入口點,而這樣一路向上委派直至 Root Class 的過程就叫做 Superclass Chain。也因為 Funnel Point 的特性,因此我們在設計時,要盡可能地保持每個類別只有一個到兩個 Designated Initializer,一來可以保持程式碼的重用性,二來也不會因為多層的繼承關係下破壞 Funnel 的結構。讓 Designated Initializer 專心負責 Stored Property 的首次賦值以及一些必要的初始化步驟,至於彈性化的介面就交給 Convenience Initializer 來張羅。

Initializer Delegation 就介紹到這,接下來的幾篇文章會陸續對 Two-phase Initialization、Class Inheritance and Initialize 以及其它幾種 Initializer 進行說明,盡請期待!

--

--