Struct:
在結(jié)構(gòu)體中方法都是靜態(tài)調(diào)用(直接調(diào)用)算利,也就意味著在在編譯連接完成之后當(dāng)前這個(gè)函數(shù)的地址就已經(jīng)確定了政供,在函數(shù)執(zhí)行的過程中就會(huì)直接去到這個(gè)地址來執(zhí)行當(dāng)前方法琢岩,這是結(jié)構(gòu)體的方法調(diào)度
Class:
相比于結(jié)構(gòu)體酝惧,在類中方法是存放在v-Table中
v-Table在sil中的表示:
decl ::= sil-vtable
sil-vtable ::= 'sil-vtable' identifier '{' sil-vtable-entry* '}'
sil-vtable-entry ::= sil-decl-ref ':' sil-linkage? sil-function-name
v-Table代碼解讀:先聲明sil-vtable這個(gè)關(guān)鍵字沈善,這個(gè)關(guān)鍵字里面包含了第一‘sil-vtable’關(guān)鍵字,第二包含一個(gè)identifier(標(biāo)識符)可以是類炼绘,然后{' sil-vtable-entry* '}代表著identifier中包含的所有方法嗅战,最后一段是方法聲明和方法名稱
驗(yàn)證方式一:匯編
源碼:
import UIKit
class LGTeacher {
func teacher() {print("teacher")}
func teacher1() {print("teacher1")}
func teacher2() {print("teacher2")}
func teacher3() {print("teacher3")}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
var t = LGTeacher()
t.teacher()
t.teacher1()
t.teacher2()
t.teacher3()
}
}
arm64匯編指令
blr: 帶返回的跳轉(zhuǎn)指令,跳轉(zhuǎn)到指令后邊跟隨寄存器中保存的地址
mov: 將某一寄存器的值復(fù)制到另一寄存器(只能用于寄存器與寄存器俺亮,或者寄存器與常量之間傳值驮捍,不能用于內(nèi)存地址)
例子:mov x1,x0 將寄存器x0的值復(fù)制到寄存器x1中
ldr: 將內(nèi)存中的值讀取到寄存器中
例子:ldr x0,[x1,x2] 將寄存器x1和寄存器x2相加作為地址脚曾,取該內(nèi)存地址的值放入寄存器x0中
str: 將寄存器中的值寫入內(nèi)存中
例子:str x0东且,[x0, x8] 將寄存器x0的值寫入內(nèi)存[x0+x8]處
br : 跳轉(zhuǎn)到某地址
圖一:
圖二:
驗(yàn)證方式二:SIL
結(jié)論:想要驗(yàn)證的是在v-table中函數(shù)地址是連續(xù)存儲(chǔ)的!1炯ァ珊泳!
子類繼承父類鲁冯,子類的v-table里面完整copy了父類里面的方法,采用的是以空間換取時(shí)間的方式色查。
關(guān)于extension中的方法薯演,調(diào)用的時(shí)候不通過v-table的方式了,是直接訪問內(nèi)存地址秧了。跟OC中是不同的
補(bǔ)充OC中的分類:
OC中方法調(diào)度是二維數(shù)組跨扮,Method_list,當(dāng)出現(xiàn)Category的時(shí)候,是將Method_list整體向后移動(dòng)Category_list的內(nèi)存空間验毡,然后重新組合成了一個(gè)新的Class衡创,這個(gè)時(shí)候會(huì)出現(xiàn)一個(gè)問題:如果class中的方法與category中的方法出現(xiàn)了重合,這個(gè)時(shí)候調(diào)用方法會(huì)優(yōu)先調(diào)用到Category中的方法晶通,原因是Category在整個(gè)Method_list的最前面璃氢。
final
final關(guān)鍵字:通過final關(guān)鍵字聲明的方法會(huì)變成直接調(diào)用
@Objc
@Objc: 暴露頭文件給Objective-c調(diào)用,并不修改當(dāng)前函數(shù)的調(diào)用方式录择,真實(shí)的狀況是這里使用@objc之后拔莱,生成了兩個(gè)相同的方法,其中一個(gè)是用@objc來標(biāo)記的隘竭,在@objc標(biāo)記的方法中調(diào)用了Swift v-table中的原方法塘秦。如果想真正的完全的給Objective-C來使用,那要使當(dāng)前類繼承NSObject动看。這個(gè)時(shí)候就ok了
Dynamic
dynamic:動(dòng)態(tài)的尊剔。如果使用dynamic修飾的方法,當(dāng)前類繼承了NSObject菱皆,那么該方法就可以使用Method Swizzing
@objc dynamic
@objc dynamic: 如果同時(shí)使用這兩個(gè)來修飾一個(gè)方法须误,那個(gè)這個(gè)方法的調(diào)度方式就會(huì)變成動(dòng)態(tài)消息轉(zhuǎn)發(fā),查看匯編代碼時(shí)當(dāng)前此方法顯示的是objc_msgSend
例子:
class LGTeacher {
dynamic func teacher() {
print("teacher")
}
}
extension LGTeacher {
@_dynamicReplacement(for: teach)
func teach1() {
print("teach1!")
}
}