利用 extension 同時客製 init 和保留 default initializer & memberwise initializer

當我們沒有定義任何 init 時,Swift 可以自動生成一些 init 方便我們生東西。比方 struct 會生成方便設定每個 property 的 memberwise initializer,而當 class & struct 的 property 在宣告時有指定初始值時,則可產生沒有參數的 default initializer,init( )。

比方以下的 Book,我們用 default initializer 生成”一個都不留”,memberwise initializer 生成”化身博士”。

struct Book {   var name = "一個都不留"   var author = "克莉絲蒂"}var newBook = Book()print(newBook)newBook = Book(name: "化身博士", author: "史帝文生")print(newBook)

不過彼得潘很愛偵探小說女王克莉絲蒂,因此特別定義一個新的 init,init(name: String)到時候只要傳入書名,即可建立克莉絲蒂的小說。

struct Book {   var name = "一個都不留"   var author = "克莉絲蒂"   init(name: String) {      self.name = name   }}var newBook = Book(name: "畸形屋")

但是一旦我們自己定義 init,Swift 就覺得我們不需要它了,不會再好心幫我們生成 default initializer & memberwise initializer 。

當然,我們可以自力自強,自己定義 default initializer & memberwise initializer。

struct Book {   var name = "一個都不留"   var author = "克莉絲蒂"   init() {   }   init(name: String, author: String) {      self.name = name      self.author = author   }   init(name: String) {      self.init(name: name, author: "克莉絲蒂")   }}
var newBook = Book()print(newBook)newBook = Book(name: "化身博士", author: "史帝文生")print(newBook)newBook = Book(name: "畸形屋")print(newBook)

但是自己寫 default initializer & memberwise initializer 實在有點煩,有沒有方法可以自己定義 init,但 Swift 還是會幫我們產生 default initializer & memberwise initializer 呢 ?

有的,我們可以在 extension 定義 init,如此即可保留 default initializer & memberwise initializer。

struct Book {   var name = "一個都不留"   var author = "克莉絲蒂"}extension Book {   init(name: String) {      self.init(name: name, author: "克莉絲蒂")   }}var newBook = Book()print(newBook)newBook = Book(name: "化身博士", author: "史帝文生")print(newBook)newBook = Book(name: "畸形屋")print(newBook)

剛剛我們看到的例子都是 struct ,class 也可以用 extension 定義 init,然後保留原本的 default initializer (class 沒有 memberwise initializer)。

class Book {   var name = "一個都不留"   var author = "克莉絲蒂"}extension Book {   convenience init(name: String, author: String) {      self.init()      self.name = name      self.author = author   }   convenience init(name: String) {      self.init()      self.name = name   }}var newBook = Book()print(newBook.name)newBook = Book(name: "化身博士", author: "史帝文生")print(newBook.name)newBook = Book(name: "畸形屋")print(newBook.name)

不過需注意 class 的 extension 只能定義 convenience init,一旦忘了加上 convenience,就會產生紅色錯誤呢。

Designated initializer cannot be declared in an extension of 'Book'; did you mean this to be a convenience initializer?

彼得潘和學生們在開發 iOS App 路上曾經解決的問題集

彼得潘的 iOS App Neverland

Written by

彼得潘的 Swift 程式設計入門,App程式設計入門作者,彼得潘的iOS App程式設計入門,文組生的iOS App程式設計入門講師,http://apppeterpan.strikingly.com

彼得潘的 Swift iOS App 開發問題解答集

彼得潘和學生們在開發 iOS App 路上曾經解決的問題集

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade