多態(tài)
結(jié)構(gòu)體struct與類class 的區(qū)別
(1)結(jié)構(gòu)體是值類型、類是引用類型
(2)類可以繼承惑芭,結(jié)構(gòu)體不能繼承
(3)結(jié)構(gòu)體的方法是編譯時(shí)確定的,而類是運(yùn)行時(shí)(多態(tài))確定的
(4)使用技巧:如果方法或者屬性继找,不需要使用到繼承遂跟,則可以使用結(jié)構(gòu)體
swift中類的多態(tài)與oc中類的多態(tài)不一樣
oc中多態(tài)是通過(guò)runtime
實(shí)現(xiàn)的,swift是通過(guò)”虛表“
的方式婴渡。
oc通過(guò)isa
指針逐層的遍歷幻锁,查找方法的實(shí)現(xiàn)
而swift是通過(guò)對(duì)象的前八個(gè)字節(jié)
找到類型信息
,類型信息里保存中所有方法函數(shù)的指針边臼,通過(guò)偏移地址值越败,獲取到對(duì)應(yīng)的方法地址,然后調(diào)用
初始化
類
硼瓣、結(jié)構(gòu)體
究飞、枚舉
都可以定義初始化器
類
有2種初始化器:指定初始化器
(designated initializer)、便捷初始化器
(convenience initializer)
/// 指定初始化器
init(parameters) {
statements
}
/// 便捷初始化器
convenience init(parameters) {
statements
}
規(guī)則
每個(gè)類至少有一個(gè)指定初始化器
堂鲤,指定初始化器是類的主要初始化器
默認(rèn)初始化器總是類的指定初始化器(init)
類偏向于少量指定初始化器
亿傅,一個(gè)類通常只有一個(gè)指定初始化器
初始化器的
相互調(diào)用規(guī)則
(1)指定初始化器
必須從它的直系父類調(diào)用指定初始化器
(2)便捷初始化器
必須從相同的類里調(diào)用一個(gè)初始化器
(3)便捷初始化器
最終必須調(diào)用一個(gè)指定初始化器
class Size {
var width : Int = 0
var height : Int = 0
/// 指定初始化器
init(width:Int,height:Int) {
self.width = width
self.height = height
}
/// 便捷初始化器
convenience init(width:Int) {
self.init(width:width,height:0)
}
/// 便捷初始化器
convenience init(height:Int) {
self.init(width:0,height:height)
}
/// 便捷初始化器
convenience init(){
self.init(width:0,height:0)
}
}
指定初始化器
必須從它的直系父類調(diào)用指定初始化器
class Person {
var age:Int = 0
init(age:Int) {
self.age = age
}
}
class Student : Person {
var score: Int = 0
/// 指定初始化器
init(age:Int, score:Int) {
/// 蘋果要求:必須先初始化自己的屬性,再調(diào)用父類的指定初始化器
self.score = score
/// 必須調(diào)用直系父類的指定初始化器
/// 這是為了數(shù)據(jù)安全瘟栖,達(dá)到每個(gè)屬性都能初始化
super.init(age: age)
}
/// 指定初始化器不能調(diào)用自己的指定初始化器
/// 因?yàn)樘O果要求指定初始化器是獨(dú)立的葵擎,不能相互調(diào)用
init(){
self.score = 0
super.init(age: 0)
}
/// 便捷初始化器可以調(diào)用自己的另外一個(gè)便捷初始化器,
/// 但最終必須能調(diào)用自己的指定初始化器
convenience init(score:Int) {
self.init(age:0,score:score)
}
}
兩段式初始化
第一階段:
初始化所有存儲(chǔ)屬性
(1)外層調(diào)用指定/便捷初始化器
(2)分配內(nèi)存給實(shí)例半哟,但為初始化
(3)指定初始化器確保當(dāng)前類定義的存儲(chǔ)屬性都初始化
(4)指定初始化器調(diào)用父類的指定初始化器酬滤,不斷向上調(diào)用,形成初始化器鏈第二階段:
設(shè)置新的存儲(chǔ)屬性值
(1)從頂部初始化器往下寓涨,鏈中的每一個(gè)指定初始化器都有機(jī)會(huì)進(jìn)一步定制實(shí)例
(2)初始化器現(xiàn)在能夠使用self(訪問(wèn)盯串、修改它的屬性,調(diào)用它的實(shí)例方法等等)
(3)最終戒良,鏈中任何便捷初始化器都有機(jī)會(huì)定制實(shí)例以及使用self
安全檢查
(1)指定初始化器必須保證在
調(diào)用父類初始化器之前
体捏,其所在類定義的所有存儲(chǔ)屬性都要初始化完成
(2)指定初始化器必須先調(diào)用父類初始化器,然后才能為繼承的屬性設(shè)置新值
(3)便捷初始化器
必須先調(diào)用同類中的其他初始化器
糯崎,然后再為任意屬性設(shè)置新值
(4)初始化器在第一階段初始化完成之前
几缭,不能調(diào)用任何實(shí)例方法
,不能讀取任何實(shí)例屬性的值
沃呢,也不能引用self
(5)直到第一階段結(jié)束年栓,實(shí)例才算完全合法
重寫初始化器
當(dāng)重寫父類的指定初始化器
時(shí),必須加上override(即使子類的實(shí)現(xiàn)是便捷初始化器)如果子類寫了一個(gè)匹配父類便捷初始化器的初始化器薄霜,不用加上override
因?yàn)楦割惖谋憬莩跏蓟饔肋h(yuǎn)不會(huì)通過(guò)子類直接調(diào)用某抓,因此竿刁,嚴(yán)格來(lái)說(shuō),子類無(wú)法重寫父類的便捷初始化器
自動(dòng)繼承
(1)如果
子類沒(méi)有自定義任何指定初始化器
搪缨,它會(huì)自動(dòng)繼承父類所有的指定初始化器
(2)如果子類提供了父類所有指定初始化器的實(shí)現(xiàn)
(要么通過(guò)繼承食拜,要么重寫),子類自動(dòng)繼承所有的父類便捷初始化器
(3)就算子類添加了更多的便捷初始化器,這寫規(guī)則任然適用
(4)子類以便捷初始化器的形式重寫父類的指定初始化器副编,也可以作為滿足規(guī)則2的一部分