- swift中的
initialization
方法實(shí)現(xiàn)中不使用return
不返回對(duì)象struct Fahrenheit { var temperature: Double init() { temperature = 32.0 } } var f = Fahrenheit() print("The default temperature is \(f.temperature)° Fahrenheit") // Prints "The default temperature is 32.0° Fahrenheit"
- 通過(guò)
initializer
創(chuàng)建初始值和在屬性定義時(shí)賦予默認(rèn)值筛圆,不會(huì)調(diào)用property observer
- 由于
init
方法的方法名必須為init
且不能重定義,所以括號(hào)內(nèi)的argument label
特別重要综看。并且如果你沒有寫压恒,系統(tǒng)會(huì)為你提供挪钓。如果你不需要贡蓖,也可以使用_去掉(和其他函數(shù)方法參數(shù)結(jié)構(gòu)一樣) - 類中的屬性必須有
default value
嘁捷,在屬性定義和構(gòu)造器中賦值躏碳,如果不賦予初始化值要標(biāo)記成可選類型哀墓。不賦值的可選類型默認(rèn)為空趁餐,可以被理解成還沒有值,可以不在構(gòu)造器中賦值篮绰。 - 常量屬性必須在定義時(shí)賦值后雷,或者在構(gòu)造器中賦值。對(duì)于類實(shí)例來(lái)說(shuō),只能在定義這個(gè)常量屬性的類中使用構(gòu)造器賦值臀突,不能再子類的構(gòu)造器中賦值勉抓。
class SurveyQuestion { let text: String var response: String? init(text: String) { self.text = text } func ask() { print(text) } } let beetsQuestion = SurveyQuestion(text: "How about beets?") beetsQuestion.ask() // Prints "How about beets?" beetsQuestion.response = "I also like beets. (But not with cheese.)"
- 當(dāng)屬性都有默認(rèn)值時(shí),且沒有自定義構(gòu)造器時(shí)候学,swift 會(huì)提供默認(rèn)構(gòu)造器藕筋。
class ShoppingListItem { var name: String? var quantity = 1 var purchased = false } var item = ShoppingListItem()
- 對(duì)于結(jié)構(gòu)體而言,當(dāng)沒有自定義構(gòu)造器的時(shí)候梳码,會(huì)自動(dòng)生成逐一成員構(gòu)造器隐圾。不同于上面的默認(rèn)構(gòu)造器,逐一成員構(gòu)造器允許屬性在定義的時(shí)候沒有默認(rèn)值边翁。如果有自定義構(gòu)造器翎承,則不會(huì)生成默認(rèn)構(gòu)造器和逐一成員構(gòu)造器,這是為了防止錯(cuò)用符匾。如果想在自定義構(gòu)造器的同時(shí)也生成默認(rèn),使用擴(kuò)展(extension)
struct Size { var width = 0.0, height = 0.0 } let twoByTwo = Size(width: 2.0, height: 2.0)
- 可以自定義多個(gè)構(gòu)造器瘩例,在復(fù)雜構(gòu)造器中使用self.init調(diào)用其他簡(jiǎn)單的自定義構(gòu)造器
struct Rect { var origin = Point() var size = Size() init() {} init(origin: Point, size: Size) { self.origin = origin self.size = size } init(center: Point, size: Size) { let originX = center.x - (size.width / 2) let originY = center.y - (size.height / 2) self.init(origin: Point(x: originX, y: originY), size: size) } } let basicRect = Rect() // basicRect's origin is (0.0, 0.0) and its size is (0.0, 0.0) let originRect = Rect(origin: Point(x: 2.0, y: 2.0), size: Size(width: 5.0, height: 5.0)) // originRect's origin is (2.0, 2.0) and its size is (5.0, 5.0) let centerRect = Rect(center: Point(x: 4.0, y: 4.0), size: Size(width: 3.0, height: 3.0)) // centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0)
- 指定構(gòu)造器和普通構(gòu)造器格式一樣啊胶,至少要有一個(gè);便利構(gòu)造器在前面加上convenience關(guān)鍵字垛贤,可有可無(wú)焰坪。通常用必不可少的指定構(gòu)造器來(lái)創(chuàng)建實(shí)例,而使用便利構(gòu)造器來(lái)個(gè)性化定制子類聘惦。例如需要多個(gè)參數(shù)的指定構(gòu)造器某饰,可以創(chuàng)建需要一個(gè)參數(shù)的便利構(gòu)造器,在實(shí)現(xiàn)中調(diào)用指定構(gòu)造器善绎,其他參數(shù)傳默認(rèn)值黔漂,做到傳入更少參數(shù)便利創(chuàng)建實(shí)例,如下
init(name: String) { self.name = name } convenience init() { self.init(name: "[Unnamed]]") }
- 關(guān)于構(gòu)造器原則:1.指定構(gòu)造器必須調(diào)用其父類指定構(gòu)造器禀酱;2.便利構(gòu)造器必須調(diào)用類中其他構(gòu)造器炬守;3.便利構(gòu)造器必須最終調(diào)用指定構(gòu)造器。簡(jiǎn)單說(shuō):指定構(gòu)造器向上代理剂跟,便利構(gòu)造器橫向代理
- swift中構(gòu)造器的兩個(gè)階段减途,第一個(gè)階段賦予所有變量默認(rèn)值,第二個(gè)階段變量在使用前靈活處理
- 構(gòu)造器的安全檢查:1.必須指定所有存儲(chǔ)變量后才可以向上調(diào)用父類構(gòu)造器曹洽;2.指定構(gòu)造器必須在繼承屬性賦值前向上調(diào)用父類構(gòu)造器鳍置,否則賦值會(huì)被覆蓋;3.便利構(gòu)造器必須先調(diào)用其他構(gòu)造器送淆,后賦值税产,原理同上;4.第一階段結(jié)束前不允許調(diào)用和讀取任何實(shí)例屬性及實(shí)例方法
- 第一階段:類調(diào)用指定或便利構(gòu)造器——為新實(shí)例分配內(nèi)存,沒有被完全初始化—— 指定構(gòu)造器為所有存儲(chǔ)屬性賦初始值砖第,所有存儲(chǔ)屬性擁有內(nèi)存——指定構(gòu)造器調(diào)用其父類構(gòu)造器執(zhí)行同樣操作——反復(fù)調(diào)用繼承樹直到頂端——直到頂端所有屬性存儲(chǔ)屬性有值之后撤卢,新實(shí)例內(nèi)存完全分配完成,第一階段結(jié)束
- 第二階段:從上往下梧兼,依次給每個(gè)指定構(gòu)造器機(jī)會(huì)定制實(shí)例放吩,更改屬性并調(diào)用實(shí)例方法,直到低端
- 指定構(gòu)造器都在第一階段羽杰,在便利構(gòu)造器調(diào)用完指定構(gòu)造器后可以修改變量渡紫,這部分是第二階段,如下
class Student { var name = "xiaoming" var old: String init() { // print("\(self.name)") 第一階段未結(jié)束考赛,實(shí)例未初始化完成惕澎,讀取self會(huì)導(dǎo)致error self.old = "16" //寫入賦值可以 在指定構(gòu)造器中設(shè)置默認(rèn)值 } convenience init(old: String) { self.init() //至此,第一階段結(jié)束 print("\(self.name)") //進(jìn)入第二階段颜骤,可以讀取self唧喉,此后為靈活處理屬性的地方 //在便利構(gòu)造器中定義個(gè)性值 self.old = old } }
- swift中子類不繼承父類的構(gòu)造方法
- 關(guān)于構(gòu)造器繼承的兩個(gè)規(guī)則
1.如果子類沒有定義任何指定構(gòu)造器,則自動(dòng)繼承父類所有指定構(gòu)造器
2.如果子類實(shí)現(xiàn)了所有父類中的指定構(gòu)造器忍抽,無(wú)論是自己定義還是由1繼承的八孝,那么子類會(huì)繼承所有父類的便利構(gòu)造器 - 使用override重載父類構(gòu)造方法,當(dāng)子類存在和父類方法名相同的方法時(shí)必須要有Override鸠项,否則會(huì)報(bào)錯(cuò)
class Bicyle: Vehicle { override init() { super.init() //至此第一階段結(jié)束干跛,子類有機(jī)會(huì)重寫初始化值 self.numberOfWheels = 2 } }
- 使用?表示可失敗構(gòu)造器,防止必要參數(shù)缺失時(shí)錯(cuò)誤的成功創(chuàng)建實(shí)例
- 嚴(yán)格說(shuō)構(gòu)造方法不返回實(shí)例祟绊,只是確保self在使用的時(shí)候被初始化完成楼入,所以對(duì)于可失敗構(gòu)造器來(lái)說(shuō),失敗返回nil牧抽,成功不用返回
struct Animal { let species: String init?(species: String){ if species.isEmpty { return nil } self.species = species } }
- 枚舉為原值自動(dòng)提供可失敗初始化方式
- 使用可失敗構(gòu)造器調(diào)用自身或父類的另一個(gè)可失敗構(gòu)造器嘉熊,可以使用新的可失敗構(gòu)造器在原可失敗構(gòu)造器上添加額外的失敗情況
class Product { let name: String init?(name: String) { if name.isEmpty{ return nil } self.name = name } } class cartItem: Product { let quantity: Int init?(name: String, quantity: Int) { if quantity < 1 { return nil } self.quantity = quantity super.init(name: name) } }
- 可使用不可失敗構(gòu)造器調(diào)用失敗構(gòu)造器,在其中給予失敗條件固定值阎姥,并使用记舆!對(duì)于確定不會(huì)失敗的可失敗構(gòu)造器進(jìn)行強(qiáng)制拆包
class Document { var name: String? init() { } init?(name: String) { if name.isEmpty { return nil } self.name = name } } class AutomaticallyNamedDocument: Document { override init() { super.init() self.name = "[Untitled]" } override init?(name: String) { super.init() if name.isEmpty { self.name = "[Untitled]" } else { self.name = name } } } class UntitledDocument: Document { override init() { super.init(name: "[Untitled]")! } }
- 使用required關(guān)鍵字來(lái)表示必備構(gòu)造器,子類也必須實(shí)現(xiàn)呼巴,不需要override關(guān)鍵字而是繼續(xù)使用required
- 使用閉包給函數(shù)屬性賦予初始值泽腮,注意閉包內(nèi)類本身沒有構(gòu)造完成,所以不能在閉包函數(shù)內(nèi)調(diào)用其他類屬性(即使屬性有默認(rèn)值)衣赶,不能在閉包內(nèi)使用self诊赊,不能在閉包內(nèi)調(diào)用其他類中函數(shù)。實(shí)際上就是給某些相對(duì)復(fù)雜的屬性使用一個(gè)新的匿名函數(shù)賦值府瞄,而由于新的匿名函數(shù)沒有參數(shù)碧磅,所以不能使用匿名函數(shù)外的變量碘箍。
struct Chessboard { let boardColors: [Bool] = { var temporaryBoard = [Bool]() var isBlack = false for i in 1...8 { for j in 1...8 { temporaryBoard.append(isBlack) isBlack = !isBlack } isBlack = !isBlack } return temporaryBoard }() func squareIsBlckAt(row: Int, column: Int) -> Bool { return boardColors[(row * 8) + column] } }
代碼示例
函數(shù)繼承樹關(guān)于構(gòu)造器的繼承以及指定構(gòu)造器和便利構(gòu)造器的應(yīng)用。
class Food {
var name: String
init(name: String) {
self.name = name
}
//提供一個(gè)帶有默認(rèn)值的便利構(gòu)造器
convenience init() {
self.init(name: "[Unnamed]]")
}
}
let namedMeat = Food.init(name: "Bacon")
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
//本類中的屬性可以在super.init前面賦值鲸郊,而父類的屬性要在super.init后賦值
self.quantity = quantity
super.init(name: name)
}
//提供一個(gè)便利構(gòu)造器不指定個(gè)數(shù)時(shí)默認(rèn)為1
//此方法實(shí)際上重載的是food中的指定構(gòu)造器
override convenience init(name: String) {
self.init(name: name, quantity: 1)
}
//和父類中的便利構(gòu)造器相同丰榴,但是不需要override重載
convenience init() {
self.init(name: "default", quantity: 0)
}
}
let oneMysteryItem = RecipeIngredient()
let oneBacon = RecipeIngredient.init(name: "Bacon")
let sixEggs = RecipeIngredient.init(name: "Eggs", quantity: 6)
class AShoppingListItem: RecipeIngredient {
var purchased = false
// 使用閉包返回一個(gè)只讀計(jì)算屬性
var description: String {
var output = "\(quantity) x \(name) "
output += purchased ? "??" : "?"
return output
}
}
var breakfaseList = [AShoppingListItem(), AShoppingListItem.init(name: "Bacon"), AShoppingListItem.init(name: "Eggs", quantity: 6)]
breakfaseList[0].name = "Orange juice"
breakfaseList[0].purchased = true
for item in breakfaseList {
print("\(item.description)")
}
補(bǔ)充幾點(diǎn)
- 方法名,參數(shù)個(gè)數(shù)秆撮,參數(shù)名完全相同的方法才算是一個(gè)方法四濒,才需要用Override重載
- 使用convenience定義的構(gòu)造器一定要調(diào)用指定構(gòu)造器,否則會(huì)報(bào)錯(cuò)
- 如果子類中定義的convenience構(gòu)造器有和父類中的某個(gè)指定構(gòu)造器方法重疊职辨,也需要使用override重載
- 如果子類中定義的convenience構(gòu)造器于父類中某個(gè)convenience方法相同盗蟆,不需要使用override重載