Swift中初始化init的方法小結(jié)
前言
我們?cè)谏钊氤跏蓟椒ㄖ埃环料仍傧胂隨wift中的初始化想要達(dá)到一種怎樣的目的。
其實(shí)就是安全。在Objective-C中,init方法是非常不安全的:沒有人能保證init只被調(diào)用一次,也沒有人保證在初始化方法調(diào)用以后,實(shí)例的各個(gè)變量都完成初始化,甚至如果在初始化里使用屬性進(jìn)行設(shè)置的話,還可能會(huì)造成各種問題。雖然Apple也明確說明了不應(yīng)該在init中使用屬性來訪問,但這并不是編譯器強(qiáng)制的,因此還是會(huì)有很多開發(fā)者犯這樣的錯(cuò)誤。
所以Swift有了超級(jí)嚴(yán)格的初始化方法。一方面,Swift強(qiáng)化了designated初始化方法的地位。Swift中不加修飾的init方法都需要在方法中保證所有非Optional的實(shí)例變量被賦值初始化,而在子類中也強(qiáng)制 (顯式或隱式地)調(diào)用super版本的designated初始化,所以無論如何走何種路徑,被初始化的對(duì)象總是可以完成完整的初始化的。
Swift 的初始化和 Objective-C 有一個(gè)很大的不同,Objective-C 默認(rèn)會(huì)給每個(gè)屬性賦一個(gè)空值,如 nil 或者 0,但 Swift 的初始化更加嚴(yán)格,需要開發(fā)者自己顯示指定類成員的初始值,否則編譯會(huì)報(bào)錯(cuò)。
結(jié)構(gòu)體初始化
如果結(jié)構(gòu)體沒有實(shí)現(xiàn)任何初始化函數(shù),Swift 默認(rèn)給生成一個(gè)包含所有成員變量的初始化構(gòu)造器。
struct RocketConfiguration { let name: String = "Athena 9 Heavy" let numberOfFirstStageCores: Int let numberOfSecondStageCores: Int let numberOfStageReuseLandingLegs: Int }
如果使用如下的代碼初始化這個(gè)結(jié)構(gòu)體:
let athena9Heavy = RocketConfiguration()
將產(chǎn)生編譯錯(cuò)誤,如下圖:
有兩種做法可以消除錯(cuò)誤,聲明結(jié)構(gòu)體成員時(shí)即賦值,如下:
struct RocketConfiguration { let name: String = "Athena 9 Heavy" let numberOfFirstStageCores: Int = 3 let numberOfSecondStageCores: Int = 1 let numberOfStageReuseLandingLegs: Int? = nil } let athena9Heavy = RocketConfiguration()
但這種情況下,成員變量無法再修改,除非將let改成var?;蛘呤褂媚J(rèn)的初始化構(gòu)造器,給每個(gè)成員賦一個(gè)初始化的值:
struct RocketConfiguration { let name: String = "Athena 9 Heavy" let numberOfFirstStageCores: Int let numberOfSecondStageCores: Int let numberOfStageReuseLandingLegs: Int } let athena9Heavy = RocketConfiguration(numberOfFirstStageCores: 3, numberOfSecondStageCores: 1, nominalBurnTime: nil)
類的初始化
和結(jié)構(gòu)體不同的是,類必須自己聲明初始化構(gòu)造器:
class LaunchSite { let name: String let coordinates: (String, String) init(name: String, coordinates: (String, String)) { self.name = name self.coordinates = coordinates } }
如果去掉上面的init函數(shù),將產(chǎn)生編譯錯(cuò)誤,如下圖:
指定構(gòu)造器(Designated Initializers)
指定構(gòu)造器對(duì)所有沒有默認(rèn)值的非可選屬性進(jìn)行初始化。
class RocketComponent { let model: String let serialNumber: String let reusable: Bool // Init #1a - Designated init(model: String, serialNumber: String, reusable: Bool) { self.model = model self.serialNumber = serialNumber self.reusable = reusable } }
初始化調(diào)用:
let payload = RocketComponent(model: "RT-1", serialNumber: "234", reusable: false)
便利構(gòu)造器(Convenience Initializers)
便利構(gòu)造器是在init前加一個(gè)關(guān)鍵子convenience,它為一些屬性提供默認(rèn)值:
// Init #1b - Convenience convenience init(model: String, serialNumber: String) { self.init(model: model, serialNumber: serialNumber, reusable: false) }
這樣,在初始化時(shí)就無需給所有屬性賦值,如下:
let fairing = RocketComponent(model: "Serpent", serialNumber: "0")
便利構(gòu)造器通常要調(diào)用類自身的便利構(gòu)造器或者指定構(gòu)造器,不管是哪種,最終都要調(diào)用指定構(gòu)造器。如下圖:
子類的初始化
class Tank: RocketComponent { let encasingMaterial: String }
這段代碼會(huì)產(chǎn)生編譯錯(cuò)誤:
encasingMaterial 沒有初始化值,Swift 的原則是,所有屬性在初始化階段都要完成賦值,因?yàn)?Swift 不會(huì)給屬性賦默認(rèn)值,需要開發(fā)者自己完成。簡(jiǎn)單做法是給encasingMaterial屬性一個(gè)默認(rèn)值:
class Tank: RocketComponent { let encasingMaterial: String = "Aluminum" } let fuelTank = Tank(model: "Athena", serialNumber:"003", reusable: true)
或者聲明一個(gè)指定構(gòu)造器:
class Tank: RocketComponent { let encasingMaterial: String init(model: String, serialNumber: String, reusable: Bool, encasingMaterial: String) { self.encasingMaterial = encasingMaterial super.init(model: model, serialNumber: serialNumber, reusable: reusable) } } let fuelTank = Tank(model: "Athena", serialNumber:"003", reusable: true, encasingMaterial: "Aluminum")
需要注意的是,子類自身屬性的初始化需要在調(diào)用父類的初始化構(gòu)造器前完成,如下代碼
init(model: String, serialNumber: String, reusable: Bool, encasingMaterial: String) { super.init(model: model, serialNumber: serialNumber, reusable: reusable) self.encasingMaterial = encasingMaterial }
將產(chǎn)生編譯錯(cuò)誤,如下圖:
父類屬性的初始化,需要在調(diào)用父類構(gòu)造器之后:如下:
init(model: String, serialNumber: String, reusable: Bool, encasingMaterial: String) { self.encasingMaterial = encasingMaterial super.init(model: model, serialNumber: serialNumber, reusable: reusable) self.model = model + "-X" }
要先調(diào)用父類的構(gòu)造器,以防止先給屬性賦值了然后才調(diào)用父類而把以前的賦值覆蓋了。若把self.model放在super.init之前,會(huì)產(chǎn)生編譯錯(cuò)誤:
初始化調(diào)用順序
- 便利構(gòu)造器需要調(diào)用類自身的便利構(gòu)造器或指定構(gòu)造器,最終要調(diào)用類自身的指定構(gòu)造器。
- 子類的指定構(gòu)造器需要調(diào)用父類的指定構(gòu)造器
如下圖:
這篇文章總結(jié)自以下兩篇文章
- Swift Tutorial: Initialization In Depth, Part 1/2
- Swift Tutorial: Initialization In Depth, Part 2/2
想了解更詳細(xì)的 Swift 初始化過程可作參考,建議大家創(chuàng)建一個(gè) playground,跑一遍文章中的例子,能加深理解。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)我們的支持。
欄 目:Swift
下一篇:Swift中defer關(guān)鍵字推遲執(zhí)行示例詳解
本文標(biāo)題:Swift中初始化init的方法小結(jié)
本文地址:http://mengdiqiu.com.cn/a1/Swift/11964.html
您可能感興趣的文章
- 01-11swift中defer幾個(gè)簡(jiǎn)單的使用場(chǎng)景詳解
- 01-11Swift利用Decodable解析JSON的一個(gè)小問題詳解
- 01-11Swift中defer關(guān)鍵字推遲執(zhí)行示例詳解
- 01-11Swift中定義單例的方法實(shí)例
- 01-11Swift利用純代碼實(shí)現(xiàn)時(shí)鐘效果實(shí)例代碼
- 01-11Swift中排序算法的簡(jiǎn)單取舍詳解
- 01-11Swift如何為設(shè)置中心添加常用功能
- 01-11Swift Json實(shí)例詳細(xì)解析
- 01-11Swift利用指紋識(shí)別或面部識(shí)別為應(yīng)用添加私密保護(hù)功能
- 01-11Swift 4.0中如何引用3.0的第三方庫


閱讀排行
- 1C語言 while語句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹的示例代碼(圣誕
- 3利用C語言實(shí)現(xiàn)“百馬百擔(dān)”問題方法
- 4C語言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 01-11Swift利用Decodable解析JSON的一個(gè)小問題
- 01-11swift中defer幾個(gè)簡(jiǎn)單的使用場(chǎng)景詳解
- 01-11Swift中初始化init的方法小結(jié)
- 01-11Swift中defer關(guān)鍵字推遲執(zhí)行示例詳解
- 01-11Swift利用純代碼實(shí)現(xiàn)時(shí)鐘效果實(shí)例代碼
- 01-11Swift中定義單例的方法實(shí)例
- 01-11Swift中排序算法的簡(jiǎn)單取舍詳解
- 01-11Swift Json實(shí)例詳細(xì)解析
- 01-11Swift如何為設(shè)置中心添加常用功能
- 01-11Swift利用指紋識(shí)別或面部識(shí)別為應(yīng)用添
隨機(jī)閱讀
- 04-02jquery與jsp,用jquery
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-10使用C語言求解撲克牌的順子及n個(gè)骰子
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-10C#中split用法實(shí)例總結(jié)
- 01-11ajax實(shí)現(xiàn)頁面的局部加載
- 01-10delphi制作wav文件的方法
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什