文森說技術

iOS, Web Development Notes
- ,

關於 Swift 初始化方法的那些小事

本文使用環境或工具版本

Xcode12.0
Swift5.3

這篇是看到 Swift Tips #5 – Custom and Compiler Generated Init 這個影片之後為了加深自己的印象的筆記。

使用 Swift 的 struct 定義一個結構體的時候,
基本上都會免費得到一個初始化方法 (initializer) 。

就像這樣,假如我們有個定義一個 Mountain 的結構體

1
2
3
4
struct Mountain {
let name: String
let height: CGFloat
}

在不需要自行定義的情形之下我們就可以自動獲得一個根據屬性定義而生成的 initializer :

1
let baguashan = Mountain(name: "八卦山", height: 97.05)

自定義 initializer

接著假如我們有個需求是,

有的山我們不知道高度,就先把它預設為零

(先不管這個邏輯合不合理 XDDD)

我們可能通常會這樣做,自己定義一個:

1
2
3
4
5
6
7
8
9
struct Mountain {
let name: String
let height: CGFloat

init(name: String) {
self.name = name
self.height = 0.0
}
}

然後這樣子初始化:

1
let yinhangshan = Mountain(name: "銀行山")

但是這時候 Xcode 會說修但幾勒,你多了一個 height 囉~

也就是發生了因為自行定義一個 initializer 後,魚與熊掌不可兼得地,我們喪失了那個免費的初始化方法,並破壞掉原本寫的程式碼。

把預設 initializer 寫出來

既然如此,沒有免費的話那就老實地把它寫出來吧

1
2
3
4
5
6
7
8
9
struct Mountain {
let name: String
let height: CGFloat

init(name: String, height: CGFloat = 0.0) {
self.name = name
self.height = height
}
}

或是勤勞一點

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct Mountain {
let name: String
let height: CGFloat

init(name: String) {
self.name = name
self.height = 0.0
}

init(name: String, height: CGFloat) {
self.name = name
self.height = height
}
}

補上這樣的實作的話, Xcode 就不會抱怨了。

利用 extension 魚與熊掌兼可得

不過其實還有一個方法可以讓附贈的 initializer 不會被影響,那就是把自定義的 initializer 寫到 extension 去。

如此一來預設的初始化方法就不會被干擾了

1
2
3
4
5
6
7
8
9
10
11
struct Mountain {
let name: String
let height: CGFloat
}

extension Mountain {
init(name: String) {
self.name = name
self.height = 0.0
}
}

結語

由於我自己是不習慣把 init 寫在 extension 裡面,因此真的要用的話可能要先過自己內心這關(笑)

不過知道這個寫法之後,或許未來可以避免多寫一些程式碼。

如果覺得這篇對你有幫助,歡迎幫忙分享給其他人 😀