經過以前的分析,結構體是值類型
,類是引用類型
。那結構體和類的方法存儲在哪裏?咱們分析一下swift
值類型對象的函數的調用方式是靜態調用
,即直接地址調用
,調用函數指針,這個函數指針在編譯、連接完成後
,當前函數的地址就已經肯定了,拿在執行代碼的過程當中就直接跳轉到這個地址來執行當前對應的方法,存放在代碼段,而結構體內部並不存放方法。所以能夠直接經過地址直接調用
。數組
類中聲明的方法是經過V-table
來進行調度的。 V-Table
在SIL
中的表示是這樣的:安全
//聲明sil vtable關鍵字
1 decl ::= sil-vtable
//sil vtable中包含 關鍵字、標識(即類名)、全部的方法
2 sil-vtable ::= 'sil_vtable' identifier '{' sil-vtable-entry* '}'
//方法中包含了聲明以及函數名稱
3 sil-vtable-entry ::= sil-decl-ref ':' sil-linkage? sil-function-na
me
複製代碼
咱們經過一個簡單的例子來看一下markdown
class LGTeacher {
func teach(){}
func teach2(){}
func teach3(){}
func teach4(){}
@objc deinit{}
init(){}
}
複製代碼
經過SIL源文件
查看其在SIL中的v-table
,以下圖所示 ide
由上圖可知函數
sil_vtable
:關鍵字LGTeacher
:代表當前是LGTeacher
class的函數表數組
,聲明在class內部
的方法在不加任何關鍵字修飾的過程當中,連續存放
在咱們當前的地址空間
中經過查看源碼發現其內部是經過for循環編碼
,而後offset+index
偏移,而後獲取method,將其存入到偏移後的內存中,從這裏能夠印證函數是連續存放
的。編碼
能夠得出結論:對於class中函數
來講,類的方法調度是經過V-Taable
,其本質就是一個連續的內存空間(數組結構)
。spa
其緣由是由於子類將父類的函數表所有繼承
了,若是此時子類增長函數
,會繼續在連續的地址中插入,假設extension函數也在函數表中
,則意味着子類也有,可是子類沒法並無相關的指針記錄函數是父類方法仍是子類方法,因此不知道方法該從哪裏插入
,致使extension中的函數沒法安全的放入子類中。因此在這裏能夠側面證實extension中的方法是直接調用的,且只屬於類,子類是沒法繼承的
。指針
子類也有其訪問權限
,只是不能繼承和重寫
。final修飾code
final
修飾的方法是直接調度
的@objc修飾
@objc
關鍵字是將swift
中的方法暴露給OC,@objc
修飾的方法是函數表調度
。OC訪問swift
,class須要繼承NSObject
。dynamic修飾 使用dynamic
的意思是能夠動態修改
,覺得着當繼承自NSObject時,可使用method-swizzling
場景:swift中實現方法交換 在swift中的須要交換的函數前,使用dynamic修飾,而後經過:@_dynamicReplacement(for: 函數符號)
進行交換,以下所示
class PDTeacher: NSObject {
dynamic func teach(){ print("teach") }
func teach2(){ print("teach2") }
func teach3(){ print("teach3") }
func teach4(){ print("teach4") }
@objc deinit{}
override init(){}
}
extension PDTeacher{
@_dynamicReplacement(for: teach)
func teach5(){
print("teach5")
}
}
複製代碼
將teach
方法替換成了teach5
struct
是值類型
,其中函數的調度屬於直接調用地址
,即靜態調度
。class
是引用類型
,其中函數的調度是經過V-Table函數表
來進行調度的,即動態調度
。extension
中的函數調度方式是直接調度
。final
修飾的函數調度方式是直接調度
。@objc
隨時的函數調度方式是函數表調度
,若是OC中須要使用,class還必須繼承NSObject
。dynamic
修飾的函數的調度方式是函數表調度
,是函數具備動態性。@objc + dynamic
組合修飾的函數調度,是執行的是objc_msgSend
流程,即動態消息轉發
。