- Swift 中的結(jié)構(gòu)體和類跟其它面向?qū)ο笳Z言一樣都有構(gòu)造函數(shù), 而OC是沒有的
- Swift 要求實(shí)例化一個(gè)結(jié)構(gòu)體或類的時(shí)候, 所有的成員變量都必須有初始值
- 構(gòu)造函數(shù)的意義就是用于初始化所有成員變量的, 而不是分配內(nèi)存, 分配內(nèi)存是系統(tǒng)幫我們做的.
- 如果結(jié)構(gòu)體中的所有屬性都有默認(rèn)值, 可以調(diào)用
()
構(gòu)造一個(gè)結(jié)構(gòu)體實(shí)例如果結(jié)構(gòu)體中的屬性沒有默認(rèn)值, 可以自定義構(gòu)造器, 并在構(gòu)造器中給所有的屬性賦值
在Swift中,定義為結(jié)構(gòu)體的類型會自動獲得由編譯器生成的默認(rèn)初始化程序——所謂的“成員構(gòu)造器”,因?yàn)榫幾g器將根據(jù)給定結(jié)構(gòu)體的成員(即其存儲的屬性)生成該初始化程序。
例如,如果我們定義了一個(gè)User
具有name
和age
屬性的結(jié)構(gòu)體,則可以使用其成員構(gòu)造器來簡單地通過傳遞這兩個(gè)屬性的值來創(chuàng)建實(shí)例:
struct User {
var name: String
var age: Int
}
let user = User(name: "韋弦", age: 9)
另一方面,當(dāng)編譯器合成成員構(gòu)造器時(shí),將完全忽略計(jì)算屬性——因此,即使我們添加一個(gè)成員屬性,我們?nèi)匀豢梢韵褚郧耙粯永^續(xù)使用上述初始化程序:
struct User {
var name: String
var age: Int
var isAdult: Bool { age >= 18 }
}
let user = User(name: "韋弦", age: 9)
從 Swift 5.1 開始,成員構(gòu)造器也考慮了默認(rèn)屬性值——這意味著,如果我們?yōu)?code>age屬性提供默認(rèn)值,則User
只需傳遞一個(gè)name
即可創(chuàng)建實(shí)例:
struct User {
var name: String
var age: Int = 18
var isAdult: Bool { age >= 18 }
}
// 有如下兩種初始化方式
let user1 = User(name: "zhy")
let user2 = User(name: "韋弦", age: 9)
如果該類型具有private
私有屬性,只要這些屬性具有默認(rèn)值,我們還是可以正常使用其成員構(gòu)造器,和上面沒有差異,但是如果私有屬性沒有默認(rèn)值,則必須手動編寫該類型的構(gòu)造器——以便能夠從外部傳入值為該屬性賦值:
struct User {
var name: String
private var age: Int
var isAdult: Bool { age >= 18 }
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
let user = User(name: "韋弦", age: 9)
不過,要記住的一件事是,成員構(gòu)造器永遠(yuǎn)不會具有高于internal
的訪問級別,這意味著我們只能在定義其類型的模塊內(nèi)部使用它們。
最初,這似乎是一個(gè)奇怪的限制,但它確實(shí)有其優(yōu)點(diǎn),因?yàn)槲覀兛梢哉f應(yīng)該始終設(shè)計(jì)供公眾使用的顯式API,而不必將它們與數(shù)據(jù)的內(nèi)部結(jié)構(gòu)聯(lián)系在一起。
因此,總而言之,在以下情況下,我們可以使用結(jié)構(gòu)體默認(rèn)生成的成員構(gòu)造器:
- 它的所有成員都是可見的或具有默認(rèn)值。
- 我們正在與定義該結(jié)構(gòu)體的模塊相同的模塊中創(chuàng)建一個(gè)實(shí)例。
所有其他情況都要求我們至少到目前為止至少手動實(shí)現(xiàn)一個(gè)初始化程序。
當(dāng)我們?yōu)榻Y(jié)構(gòu)體創(chuàng)建便利構(gòu)造器的時(shí)候,我們可以在 擴(kuò)展extension
中聲明該便利構(gòu)造器,這樣做的好處是,當(dāng)我們定義一些便利構(gòu)造器方便初始化的同時(shí),不會覆蓋編譯器生成的成員構(gòu)造器:
struct User {
var name: String
var gender: Gender
var age: Int
var isAdult: Bool { age >= 18 }
enum Gender {
case man,woman,other
}
}
extension User {
init(name: String, age: Int) {
self.init(name: name, gender: .man, age: 18)
}
}
// 可以有如下兩種初始化方法
let user1 = User(name: "韋弦", age: 9)
let user2 = User(name: "zhy", gender: .man, age: 18)
如果直接寫在結(jié)構(gòu)體內(nèi),則初始化 user2
代碼會報(bào)錯(cuò),只剩下新聲明的便利構(gòu)造器。