異變方法
值類(lèi)型屬性不能被自身的實(shí)例方法修改
struct Point {
? ? var x = 0.0
? ? var y = 0.0
? ? func test() {
? ? ? ? print(x)
? ? }
? ? mutating func moveBy(x deltaX: Double, y deltaY: Double) {
? ? ? ? x += deltaX
? ? ? ? y += deltaY
? ? }
}
mutating關(guān)鍵字解析
轉(zhuǎn)化為中間語(yǔ)言
shell 腳本語(yǔ)言
swiftc -emit-sil -Onone -target x86_64-apple-ios14.2-simulator -sdk $(xcrun --show-sdk-path --sdk iphonesimulator) ${SRCROOT}/swiftDemo2/ViewController.swift > ./ViewController.sil && open ViewController.sil
ViewController.sil
還原sīl的混編字符串
xcrun swift-demangle?s14ViewController5PointV4testyyF
// Point.test()
sil hidden @$s14ViewController5PointV4testyyF : $@convention(method) (Point) -> ()
debug_value %0 : $Point, let, name "self", argno 1 // id: %1
偽代碼 let self =?Point
// Point.moveBy(x:y:)
sil hidden @$s14ViewController5PointV6moveBy1x1yySd_SdtF : $@convention(method) (Double, Double, @inout Point) -> ()
debug_value_addr %2 : $*Point, var, name "self", argno 3 // id: %5
偽代碼 var self = &Point
mutating是將傳入的?self?被標(biāo)記為?inout?參數(shù)谷醉。
方法調(diào)度
class LGTeacher {
?? func teach() {
? ? ? print("teach")
?? }
}
匯編基本指令
bl?跳轉(zhuǎn)到某地址(有返回)
blr?跳轉(zhuǎn)到某地址(無(wú)返回)
mov?x20, x0 將寄存到x0的值復(fù)制到寄存器20中
ldr x0,?[x1, x2] 將寄存器x1和寄存器x2的值相加作為地址,取該地址的值放入到寄存器x0中
teach方法匯編斷點(diǎn)分析
1. bl 0x100f3da28 返回一個(gè)LGTeacher實(shí)例對(duì)象
函數(shù)返回值是放在x0寄存器里面的催跪,x0存放LGTeacher實(shí)例對(duì)象
2. ldr x8, [x0] 將x0的第一個(gè)8字節(jié)缝驳,放入到x8中
x8放入LGTeacher實(shí)例對(duì)象的 metadata
3. ldr x8, [x8, #0x50]?LGTeacher的metadata + 50
4. bl x8 執(zhí)行函數(shù)
teach函數(shù)的調(diào)用過(guò)程:找到?Metadata?席揽,確定函數(shù)地址(metadata + 偏移量)尼摹, 執(zhí)行函數(shù)
類(lèi)的方法是函數(shù)表調(diào)度
class LGTeacher {
?? func teach() {
? ? ? print("teach")
?? }
?? func teach1() {
? ? ? print("teach1")
?? }
?? func teach2() {
? ? ? print("teach2")
?? }
}
let t = LGTeacher()
? ? ? t.teach()
? ? ? t.teach1()
? ? ? t.teach2()
?teach跃惫,?teach1应又,?teach2 方法是連續(xù)的囚玫,猜想放在函數(shù)表中的
通過(guò)sil文件驗(yàn)證
sil_vtable LGTeacher {
? #LGTeacher.teach: (LGTeacher) -> () -> () : @$s14ViewController9LGTeacherC5teachyyF // LGTeacher.teach()
? #LGTeacher.teach1: (LGTeacher) -> () -> () : @$s14ViewController9LGTeacherC6teach1yyF // LGTeacher.teach1()
? #LGTeacher.teach2: (LGTeacher) -> () -> () : @$s14ViewController9LGTeacherC6teach2yyF // LGTeacher.teach2()
? #LGTeacher.init!allocator: (LGTeacher.Type) -> () -> LGTeacher : @$s14ViewController9LGTeacherCACycfC // LGTeacher.__allocating_init()
? #LGTeacher.deinit!deallocator: @$s14ViewController9LGTeacherCfD // LGTeacher.__deallocating_deinit
}
類(lèi)里面本身方法是函數(shù)表調(diào)度
擴(kuò)展方法是靜態(tài)分發(fā)
extension LGTeacher {
?? func teach3() {
? ? ? print("teach3")
?? }
}
直接調(diào)用內(nèi)存地址
方法調(diào)度總結(jié)
影響函數(shù)派發(fā)方式
1. final: 添加了 final 關(guān)鍵字的函數(shù)無(wú)法被重寫(xiě)喧锦,使用靜態(tài)派發(fā),不會(huì)在 vtable 中出現(xiàn)抓督,且 對(duì) objc 運(yùn)行時(shí)不可見(jiàn)燃少。?
class LGTeacher {
?? final func teach() {
? ? ? print("teach")
?? }
?? func teach1() {
? ? ? print("teach1")
?? }
}
2. dynamic: 函數(shù)均可添加 dynamic 關(guān)鍵字,為非objc類(lèi)和值類(lèi)型的函數(shù)賦予動(dòng)態(tài)性铃在,但派發(fā) 方式還是函數(shù)表派發(fā)阵具。?
class LGTeacher {
?? dynamic func teach() {
? ? ? print("teach")
?? }? ?
}
extension LGTeacher {
?? @_dynamicReplacement(for: teach)
?? func teach3() {
? ? ? print("teach3")
?? }
}
3. @objc: 該關(guān)鍵字可以將Swift函數(shù)暴露給Objc運(yùn)行時(shí)碍遍,依舊是函數(shù)表派發(fā)。?
與oc 混編
class LGTeacher: NSObject {
?? @objc func teach() {
? ? ? print("teach")
?? }? ?
}
1.繼承NSObject
2. 加?@objc
查看橋接文件
1.
2. ->Generated Interface
4. @objc + dynamic: 消息派發(fā)的方式 , 支持runtime,方法轉(zhuǎn)換