版本記錄
| 版本號 | 時(shí)間 |
|---|---|
| V1.0 | 2017.07.30 |
前言
我是swift2.0的時(shí)候開始接觸的,記得那時(shí)候還不是很穩(wěn)定,公司的項(xiàng)目也都是用oc做的,并不對swift很重視,我自己學(xué)了一段時(shí)間,到現(xiàn)在swift3.0+已經(jīng)出來了,自己平時(shí)也不寫,忘記的也差不多了,正好項(xiàng)目這段時(shí)間已經(jīng)上線了,不是很忙,我就可以每天總結(jié)一點(diǎn)了,希望對自己對大家有所幫助。在總結(jié)的時(shí)候我會(huì)對比oc進(jìn)行說明,有代碼的我會(huì)給出相關(guān)比對代碼。
1. swift簡單總結(jié)(一)—— 數(shù)據(jù)簡單值和類型轉(zhuǎn)換
2. swift簡單總結(jié)(二)—— 簡單值和控制流
3. swift簡單總結(jié)(三)—— 循環(huán)控制和函數(shù)
4. swift簡單總結(jié)(四)—— 函數(shù)和類
5. swift簡單總結(jié)(五)—— 枚舉和結(jié)構(gòu)體
6. swift簡單總結(jié)(六)—— 協(xié)議擴(kuò)展與泛型
7. swift簡單總結(jié)(七)—— 數(shù)據(jù)類型
8. swift簡單總結(jié)(八)—— 別名、布爾值與元組
9. swift簡單總結(jié)(九)—— 可選值和斷言
10. swift簡單總結(jié)(十)—— 運(yùn)算符
11. swift簡單總結(jié)(十一)—— 字符串和字符
12. swift簡單總結(jié)(十二)—— 集合類型之?dāng)?shù)組
13. swift簡單總結(jié)(十三)—— 集合類型之字典
14. swift簡單總結(jié)(十四)—— 控制流
15. swift簡單總結(jié)(十五)—— 控制轉(zhuǎn)移語句
16. swift簡單總結(jié)(十六)—— 函數(shù)
17. swift簡單總結(jié)(十七)—— 閉包(Closures)
18. swift簡單總結(jié)(十八)—— 枚舉
19. swift簡單總結(jié)(十九)—— 類和結(jié)構(gòu)體
20. swift簡單總結(jié)(二十)—— 屬性
21. swift簡單總結(jié)(二十一)—— 方法
22. swift簡單總結(jié)(二十二)—— 下標(biāo)腳本
23. swift簡單總結(jié)(二十三)—— 繼承
24. swift簡單總結(jié)(二十四)—— 構(gòu)造過程
構(gòu)造過程
上一篇講構(gòu)造過程沒有講完,下面我們繼續(xù)看下面兩個(gè)方面。
- 類的繼承和構(gòu)造過程
- 通過閉包和函數(shù)來設(shè)置屬性的默認(rèn)值
類的繼承和構(gòu)造過程
類里面的所有存儲(chǔ)型屬性,包括所有繼承自父類的屬性,都必須在構(gòu)造過程中設(shè)置初始值。swift提供了兩種類型的類構(gòu)造器來確保所有類實(shí)例中存儲(chǔ)型屬性都能獲得初始值,分別是指定構(gòu)造器和便利構(gòu)造器。
1. 指定構(gòu)造器和便利構(gòu)造器
指定構(gòu)造器是類中最主要的構(gòu)造器,一個(gè)指定構(gòu)造器將初始化類中提供的所有屬性,并根據(jù)父類鏈往上調(diào)用父類的構(gòu)造器來實(shí)現(xiàn)父類的初始化。
每一個(gè)類都必須擁有至少一個(gè)指定構(gòu)造器,在某些情況下,許多類通過繼承了父類中的指定構(gòu)造器而滿足了這個(gè)條件。
便利構(gòu)造器時(shí)類中比較次要的、輔助型的構(gòu)造器,你可以定義便利構(gòu)造器來調(diào)用同一個(gè)類中的指定構(gòu)造器,并為其參數(shù)提供默認(rèn)值,你也可以定義便利構(gòu)造器來創(chuàng)建一個(gè)特殊用途或特定輸入的實(shí)例。
一般只在必要的時(shí)候才為類提供便利構(gòu)造器。
2. 構(gòu)造器鏈
為簡化指定構(gòu)造器和便利構(gòu)造器之間的調(diào)用關(guān)系,swift采用以下三條規(guī)則來限制構(gòu)造器之間的代理調(diào)用。
- 指定構(gòu)造器必須調(diào)用其直接父類的指定構(gòu)造器
- 便利構(gòu)造器必須調(diào)用同一類中定義的其他構(gòu)造器
- 便利構(gòu)造器必須最終以調(diào)用一個(gè)指定構(gòu)造器結(jié)束
或者可以這么記錄
- 指定構(gòu)造器必須總是向上代理
- 便利構(gòu)造器必須總是橫向代理
具體如下所所示:

這里可以看到:
- 父類中包含一個(gè)指定構(gòu)造器和兩個(gè)便利構(gòu)造器,其中一個(gè)變遍歷構(gòu)造器就調(diào)用了另外一個(gè)便利構(gòu)造器,而后者又調(diào)用了唯一的指定構(gòu)造器。
- 子類中包含兩個(gè)指定構(gòu)造器和一個(gè)便利構(gòu)造器,便利構(gòu)造器必須調(diào)用兩個(gè)指定構(gòu)造器中的任意一個(gè)。
- 上圖中展示的構(gòu)造器都可以用來完整創(chuàng)建對應(yīng)類的實(shí)例,這些規(guī)則只在實(shí)現(xiàn)類的定義時(shí)有影響。
在看一下下面的四個(gè)類的例子,演示指定構(gòu)造器時(shí)如何在類層級中充當(dāng)“管道”的作用,在類的構(gòu)造器鏈上簡化了類之間的相互關(guān)系。

3. 兩段式構(gòu)造過程
swift中類的構(gòu)造過程包含連個(gè)階段:第一階段,每個(gè)存儲(chǔ)型屬性通過引入它們的類的構(gòu)造器來設(shè)置初始值,當(dāng)每一個(gè)存儲(chǔ)型屬性值確定后;第二個(gè)階段,它給每個(gè)類一次機(jī)會(huì)在新實(shí)例準(zhǔn)備使用之前進(jìn)一步定制它們的存儲(chǔ)型屬性。
注意:swift的兩段式構(gòu)造過程和OC中的構(gòu)造過程類似,主要區(qū)別在與階段1,OC給每一個(gè)屬性賦值為0或空值,swift的構(gòu)造流程則更加靈活,它允許你設(shè)置定制的初始值,并自如應(yīng)對某些屬性不能以0或nil作為合法默認(rèn)值的情況。
swift編譯器將執(zhí)行4中有效的安全檢查,確保兩段式構(gòu)造過程能順利完成。
- 安全檢查1:指定構(gòu)造器必須保證它所在類引入的所有屬性都必須先初始化完成,之后才能將其他構(gòu)造任務(wù)向上代理給父類中的構(gòu)造器。一個(gè)對象的內(nèi)存只有在其所有存儲(chǔ)型確定之后才能完成初始化,為滿足這一點(diǎn),指定構(gòu)造器必須保證它所在類引入的屬性在它往上代理之前完成初始化。
- 安全檢查2:指定構(gòu)造器必須先向上代理調(diào)用父類構(gòu)造器,然后再為繼承的屬性設(shè)置新值,如果不這么做,指定構(gòu)造器賦予的新值將被父類中的構(gòu)造器所覆蓋。
- 安全檢查3:便利構(gòu)造器必須先代理調(diào)用同一類中的其他構(gòu)造器,然后再為任意屬性賦新值,如果不這么做,便利構(gòu)造器的新值將被同一類中其他指定構(gòu)造器所覆蓋。
- 安全檢查4:構(gòu)造器在第一階段完成之后,不能調(diào)用任何實(shí)例方法,不能讀取任何示例屬性的值,
self的值不能被引用。
下面是兩段式構(gòu)造過程中基于上述安全檢查的構(gòu)造流程展示。
階段1:
- 某個(gè)指定構(gòu)造器或便利構(gòu)造器被調(diào)用
- 完成新實(shí)例內(nèi)存分配,但此時(shí)內(nèi)存還沒被初始化
- 指定構(gòu)造器確保其所在類引入的所有存儲(chǔ)型屬性都已賦初值,存儲(chǔ)型屬性所屬的內(nèi)存完成初始化
- 指定構(gòu)造器將調(diào)用父類的構(gòu)造器,完成父類屬性的初始化
- 這個(gè)調(diào)用父類構(gòu)造器的過程沿著構(gòu)造器鏈一直往上執(zhí)行,直到達(dá)到構(gòu)造器最頂部
- 當(dāng)?shù)竭_(dá)了最頂部,且已確保所有實(shí)例包含的存儲(chǔ)型屬性都已經(jīng)賦值,這個(gè)實(shí)例的內(nèi)存被認(rèn)為已經(jīng)完全初始化完成,1階段完成。
階段2
- 從頂部構(gòu)造器鏈一直往下,每個(gè)構(gòu)造器鏈中類的指定構(gòu)造器都有機(jī)會(huì)進(jìn)一步定制實(shí)例,構(gòu)造器此時(shí)可以使用
self,修改它的屬性并調(diào)用實(shí)例方法等。 - 最終,任意構(gòu)造器鏈中的便利構(gòu)造器可以有機(jī)會(huì)定制實(shí)例和使用
self
下面圖展示的子類和父類之間構(gòu)造的階段1

構(gòu)造過程從對子類中一個(gè)便利構(gòu)造器的調(diào)用開始,這個(gè)便利構(gòu)造器此時(shí)沒法修改任何屬性,它把構(gòu)造任務(wù)代理給同一個(gè)類中的指定構(gòu)造器,指定構(gòu)造器將確保所有子類的屬性都有值,然后它將調(diào)用父類的指定構(gòu)造器,并沿著構(gòu)造器鏈一直往上完成父類的構(gòu)建過程。一旦父類中所有屬性都有了初始值,實(shí)例的內(nèi)存被認(rèn)為是完全初始化,階段1完成。
下面看一下階段2

4. 構(gòu)造器的繼承和重載
與OC不同的是,swift的子類不會(huì)默認(rèn)繼承父類的構(gòu)造器,swift的這種機(jī)制,可以防止一個(gè)父類的簡單構(gòu)造器被一個(gè)更專業(yè)的子類繼承,并被錯(cuò)誤的用來創(chuàng)建子類的實(shí)例。
假如你希望自定義的子類中能實(shí)現(xiàn)一個(gè)或多個(gè)跟父類相同的構(gòu)造器,也許是為了完成一些定制的構(gòu)造過程,你可以在你定制的子類提供和重載與父類相同的構(gòu)造器,如果你重載的構(gòu)造器是一個(gè)指定構(gòu)造器,你可以在子類里重載它的實(shí)現(xiàn),并在自定義版本的構(gòu)造器中調(diào)用父類版本的構(gòu)造器,如果你重載的構(gòu)造器是一個(gè)便利構(gòu)造器,你的重載過程必須通過調(diào)用同一類中提供的其他指定構(gòu)造器來實(shí)現(xiàn)。
注意: 與方法、屬性和下標(biāo)不同,在重載構(gòu)造器時(shí)你沒必要使用關(guān)鍵字override
5. 自動(dòng)構(gòu)造器的繼承
子類不會(huì)默認(rèn)繼承父類的構(gòu)造器,但是如果特定條件可以滿足,父類構(gòu)造器可以被自動(dòng)繼承。
假如要為子類中引入的任意新屬性提供默認(rèn)值,請遵守以下2個(gè)規(guī)則。
規(guī)則1
如果子類沒有定義任何指定構(gòu)造器,它將自動(dòng)繼承所有父類的指定構(gòu)造器。
規(guī)則2
如果子類提供了所有父類指定構(gòu)造器的實(shí)現(xiàn),不管是通過規(guī)則1繼承過來的,還是通過自定義實(shí)現(xiàn)的,它將自動(dòng)繼承所有父類的便利構(gòu)造器。
即使你在子類中添加了更多的便利構(gòu)造器,這兩條規(guī)則仍然適用,
注意:子類可以通過部分滿足規(guī)則2的方式,使用子類便利構(gòu)造器來實(shí)現(xiàn)父類的指定構(gòu)造器。
6. 指定構(gòu)造器和便利構(gòu)造器語法
類的指定構(gòu)造器寫法和值類型簡單構(gòu)造器一樣,如下所示:
init(parameter){
statements
}
便利構(gòu)造器也是一樣寫法,但是需要在init關(guān)鍵字之前放置convenience關(guān)鍵字。
convenience init(parameter){
statements
}
7. 指定構(gòu)造器和便利構(gòu)造器實(shí)戰(zhàn)
下面將會(huì)代碼展示指定構(gòu)造器、便利構(gòu)造器和自動(dòng)構(gòu)造器的繼承。
先提供基類Food,是一個(gè)簡單的用來封裝食物名字的類,看代碼。
class Food {
var name : String
init(name : String) {
self.name = name
}
convenience init() {
self.init(name: "Unnamed")
}
}
下面看一下,Food類的構(gòu)造器鏈:

類沒有提供一個(gè)逐一成員構(gòu)造器,所以Food類提供了一個(gè)接受單一參數(shù)name的指定構(gòu)造器,這個(gè)構(gòu)造器可以使用一個(gè)特定的名字創(chuàng)建實(shí)例。
class JJPracticeVC: UIViewController {
override func viewDidLoad()
{
super.viewDidLoad()
view.backgroundColor = UIColor.lightGray
let nameMeat = Food(name: "Bacon")
print(nameMeat.name)
}
}
下面看輸出結(jié)果
Bacon
Food類構(gòu)造器init(name : String)被定義為一個(gè)指定構(gòu)造器,能確保新Food實(shí)例中存儲(chǔ)型屬性都被初始化,Food類沒有父類,所以init(name : String)構(gòu)造器不需要調(diào)用super.init()來完成構(gòu)造。
Food類也提供了一個(gè)沒有參數(shù)的便利構(gòu)造器init(),這個(gè)init()構(gòu)造器為新食物提供了一個(gè)默認(rèn)的占位名字,通過代理調(diào)用同一個(gè)類中定義的指定構(gòu)造器init(name : String)并給參數(shù)name傳值"Unnamed"來實(shí)現(xiàn)。
class JJPracticeVC: UIViewController {
override func viewDidLoad()
{
super.viewDidLoad()
view.backgroundColor = UIColor.lightGray
let nameMeat = Food()
print(nameMeat.name)
}
}
下面看輸出結(jié)果
Unnamed
接著定義第二個(gè)類,繼承自Food,擁有Int類型的數(shù)量屬性quantity還有就是從Food繼承過來的name屬性。并且也定義了兩個(gè)構(gòu)造器來創(chuàng)建實(shí)例。
class RecipIngredient: Food {
var quantity : Int
init(name : String, quantity : Int){
self.quantity = quantity
super.init(name: name)
}
override convenience init(name: String) {
self.init(name: name, quantity: 1)
}
}
下面展示的是RecipIngredient的構(gòu)造器鏈。

RecipIngredient類有一個(gè)指定構(gòu)造器init(name : String, quantity : Int),它用來產(chǎn)生新的RecipIngredient實(shí)例,隨后,構(gòu)造器將任務(wù)向上代理給父類Food的init(name : String),這個(gè)過程滿足兩段式構(gòu)造過程的安全檢查1。
RecipIngredient類也定義了一個(gè)便利構(gòu)造器init(name: String),這個(gè)便利構(gòu)造器是將任務(wù)代理給了同一個(gè)類中的指定構(gòu)造器。
注意:RecipIngredient的便利構(gòu)造器init(name: String)和Food中指定構(gòu)造器init(name: String)有相同的參數(shù),因?yàn)檫@個(gè)便利構(gòu)造器重寫要父類的指定構(gòu)造器init(name: String),必須加override。
以下三種方法都可以實(shí)例化RecipIngredient
class JJPracticeVC: UIViewController {
override func viewDidLoad()
{
super.viewDidLoad()
view.backgroundColor = UIColor.lightGray
let oneInstance = RecipIngredient()
print(oneInstance.quantity)
print(oneInstance.name)
let twoInstance = RecipIngredient(name: "egg")
print(twoInstance.quantity)
print(twoInstance.name)
let threeInstance = RecipIngredient(name: "egg", quantity: 10)
print(threeInstance.quantity)
print(threeInstance.name)
}
}
下面看輸出結(jié)果
1
Unnamed
1
egg
10
egg
下面看最后一個(gè)類,繼承自RecipIngredient,類中引入了一個(gè)布爾類型的屬性purchased,還添加了一個(gè)計(jì)算型屬性description,下面看代碼。
class ShoppiingListItem: RecipIngredient {
var purchased = false
var description : String{
var output = "\(quantity) x \(name)"
output += purchased ? "買" : "不買"
return output
}
}
ShoppiingListItem為自己的所有屬性都提供了默認(rèn)值,并且自己沒有定義任何構(gòu)造器,ShoppiingListItem將自動(dòng)繼承所有父類中的指定構(gòu)造器和便利構(gòu)造器。
下面看一下三個(gè)類的構(gòu)造器鏈。

可以使用全部三個(gè)繼承來的構(gòu)造器創(chuàng)建ShoppiingListItem實(shí)例。
class JJPracticeVC: UIViewController {
override func viewDidLoad()
{
super.viewDidLoad()
view.backgroundColor = UIColor.lightGray
var breakfastList = [
ShoppiingListItem(),
ShoppiingListItem(name: "bread"),
ShoppiingListItem(name: "egg", quantity: 10)
]
breakfastList[0].name = "orange juice"
breakfastList[0].purchased = true
for item in breakfastList {
print(item.description)
}
}
}
下面看輸出結(jié)果
1 x orange juice買
1 x bread不買
10 x egg不買
通過閉包和函數(shù)來設(shè)置屬性的默認(rèn)值
如果某個(gè)存儲(chǔ)型屬性的默認(rèn)值需要特別定制,你就可以使用閉包或全局函數(shù)來為其屬性提供定制的默認(rèn)值,每當(dāng)這個(gè)屬性所屬的新類型實(shí)例創(chuàng)建時(shí),對應(yīng)的閉包或者函數(shù)會(huì)被調(diào)用,而它們的返回值會(huì)當(dāng)做默認(rèn)值賦值給這個(gè)屬性。
這種類型的閉包或函數(shù)一般會(huì)創(chuàng)建一個(gè)跟屬性類型相同的臨時(shí)變量,然后修改它的值以滿足預(yù)期的初始狀態(tài),最后將這個(gè)臨時(shí)變量的值作為屬性的默認(rèn)值進(jìn)行返回。
下面看一下調(diào)用格式。
class SomeClass{
let someProperty : SomeType = {
//在這個(gè)閉包中給someProperty創(chuàng)建一個(gè)默認(rèn)值
//someValue必須和SomeType類型相同
return someValue
}()
}
注意:
- 閉包結(jié)尾的大括號后面接一對空的小括號,這是用來告訴
swift需要立即執(zhí)行此閉包,如果你忽略了這對括號,相當(dāng)于是將閉包本身作為值賦值給了屬性,而不是將閉包的返回值賦值給屬性。 - 如果你使用閉包來初始化屬性的值,請記住在閉包執(zhí)行時(shí),實(shí)例的其他部分都還沒有初始化,這意味著你不能夠在閉包里訪問其他的屬性,就算這個(gè)屬性有默認(rèn)值也不允許,同樣,你也不能用隱式
self屬性,或者調(diào)用其他的實(shí)例方法。
看下面的結(jié)構(gòu)體定義了西洋跳棋游戲的棋盤。

下面看一下代碼
struct Checkboard {
let boardColors : [Bool] = {
var temporaryBorad = [Bool]()
var isBlack = false
for i in 1...10{
for j in 1...10 {
temporaryBorad.append(isBlack)
isBlack = !isBlack
}
isBlack = !isBlack
}
return temporaryBorad
}()
func squareIsBlackAtRow(row : Int, column : Int) -> Bool {
return boardColors[(10 * row) + column]
}
}
新的Checkboard實(shí)例創(chuàng)建時(shí),對應(yīng)的賦值閉包會(huì)執(zhí)行,一系列顏色值會(huì)被計(jì)算出來作為默認(rèn)值賦值給boardColors,閉包會(huì)返回臨時(shí)數(shù)組temporaryBorad,這個(gè)返回值會(huì)被保存到boardColors中,并可以通過工具函數(shù)squareIsBlackAtRow返回。
下面我們就調(diào)用下看看。
class JJPracticeVC: UIViewController {
override func viewDidLoad()
{
super.viewDidLoad()
view.backgroundColor = UIColor.lightGray
let checkBoard = Checkboard()
print(checkBoard.squareIsBlackAtRow(row: 0, column: 1))
print(checkBoard.squareIsBlackAtRow(row: 9, column: 9))
}
}
下面看輸出結(jié)果
true
false
后記
未完,待續(xù)~~~
