Swift 3 基礎 — Class (part 3–2.)

Subclass Initializer: Designated , Convenience, Implicit

上一個章節我們把 superclass / base class 的比較常遇到的情境都示範給大家看過了一次,不知道有沒有被這些初始化搞得頭大了呢?

請大家再深呼吸,靜下心來,在 subclass 的世界裡 initializer 會變得更複雜一點

沒關係,如果您還沒完全理解的話,可以來信或直接打給客服,由小弟親身為您示範(半夜別打給我)…

首先,請大家看到這張由 Apple 官方製作的精美圖片 (並把它放在心裡膜拜)。

不知道各位有沒有發現兩個重點:

  1. subclass 的 designated initializer 只能指定到 superclass 的 designated initializer。
  2. Convenience initializer 永遠都只能委派到同一個 class 的 designated initializer,如果有 designated initializers。

好,接下來,進入我們的正題,在 subclass 的世界裡,會有以下幾種初始化情境:

  1. No declared initializer:

如果 subclass 沒有自己的 initializer 的情況下,那個這個 class 就會繼承自 superclass 所有 initializer ( subclass 也不會有 implicit initializer init() ):

使用 Blog 當作 superclass:

再以 MyBlog 繼承他,並不寫入任何的 initializer:

我們可以知道, MyBlog class 繼承了 Blog 的所有 initializers。


2. Convenience initializer only:

在 subclass 裡沒有宣告 designated initializers,使用 convenience initializer 可以直接使用 self 指定到 designated initializers:

假設我們有個 superclass Cat :

以及繼承他的 subclass HappyCat :

把它實例化出來就可以知道裡面是怎麼樣的去呼叫 superclass 的 designated initializer :

let happyCat = HappyCat()
// 0 
// 3

也可以指定到 convenience initializer:

疑!剛剛那張圖不是說,convenience 只能指定到同一個 class 的 designated 或 convenience 嗎?怎麼現在又可以了,到底發生什麼事?

到底是什麼巫術!!

其實,仔細想想剛剛的問題以及上一個範例,在瞧瞧這個 AngryCat

破案了!

這個 AngryCat 並沒有建立自己的 designated initializers ,所以所有的 initializers 都是繼承自 superclass 而來的,所以我們可以使用 self 來呼叫 designated 與 convenience ,且都發生在 AngryCat ,而這也是 convenience initializer 的工作。


3. Designated initializer:

如果你在 subclass 建立了 designated initializer,上面的兩個規則就再也不適用了。

一旦你建立了 designated initializer ,所有的 initializer 來自 superclass 都不會在繼承,而是以 subclass 明確定義的 initializer 為主。

在 subclass 的 designated initializers 必須要遵守下列的限制:

  • 確保在 subclass 的所有 stored properties 都賦予初始值。
  • 必須呼叫 superclass 的 designated initializer,透過 super.init(...)

RedCat 明確的定義了一個 designated initializer,所以 superclass 的所有的 initializer 就不會被 RedCat 繼承,必須要透過 super 來賦予所有繼承自 superclass 的 stored properties。


4. Designated initializer and Convenience initializer

如果 subclass 有 designated 與 convenience ,convenience 依然可以套用前一章所提到的規則:

Convenience initializer 必須委派到 designated initializer,且必須是同一個 class 的 designated initializer,且被 convenience initializer 修改到的 stored properties 必須為 var

上述代表在 subclass 裡的 convenience initializer 必須要直接呼叫 designated 透過 self.init(...)或者間接的鏈結到 designated initializer 。

先觀察上述的 designated initializer 可以發現到,若 subclass 有自己的stored properties,必須透過 self 賦予自己的 stored properties 初始值在呼叫 superclass 的 designated initializer。

5. Override Initializer

Subclass 可以複寫 Superclass 的 initializer,透過在 init 前加上前綴 override 在複寫時會有兩種規範:

  • 這個 initializer 吻合 superclass 的 designated initializer,必須標記 override,可為 designated 或 convenience。
  • 這個 initializer 吻合 superclass 的 convenience initializer,不能標記 override,可以為 designate 或 convenience。

下面這個範例示範當一個是 override convenience ,另一個是 override designated ,大家可以看看有什麼差別:

呼!看了這麼多的初始化規則,有沒有覺得超頭痛呢?

其實在真正實作的時候忘記也沒關係,因為 Xcode 會打你的臉,直到你完全修正為止,很貼心吧??

這次的教學就到這邊為止,如果有什麼錯誤需要指正的地方,請直接告訴我或在下方留言。

謝謝您的閱讀!

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.