1. 程式人生 > >swift class的動態派發

swift class的動態派發

ive table unbox sil 函數 wikipedia 查找 return world

一、測試代碼

class BaseCallClass{

func NormalCall(){}

@objc func OcCall(){}

@objc dynamic func OcDynamicCall(){}

}

class DerivedCallClass:BaseCallClass{

override func NormalCall(){}

@objc override func OcCall(){}

@objc dynamic override func OcDynamicCall(){}

}

func FuncTest(object:BaseCallClass)

{

object.NormalCall()

object.OcCall()

object.OcDynamicCall()

}

func DoneTest(){

FuncTest(object: BaseCallClass())

FuncTest(object: DerivedCallClass())

}

二、命令行

swiftc -emit-sil DispatchCall.swift | xcrun swift-demangle > DispatchCall.silgen

cat DispatchCall.silgen

三、虛函數表

虛函數表中,函數的名稱都以:基類+函數名稱的形式定義;

同時映射到具體的函數;

sil_vtable BaseCallClass {

#BaseCallClass.NormalCall!1: (BaseCallClass) -> () -> () : @DispatchCall.BaseCallClass.NormalCall() -> () // BaseCallClass.NormalCall()

#BaseCallClass.OcCall!1: (BaseCallClass) -> () -> () : @DispatchCall.BaseCallClass.OcCall() -> () // BaseCallClass.OcCall()

}

sil_vtable DerivedCallClass {

#BaseCallClass.NormalCall!1: (BaseCallClass) -> () -> () : @DispatchCall.DerivedCallClass.NormalCall() -> () [override] // DerivedCallClass.NormalCall()

#BaseCallClass.OcCall!1: (BaseCallClass) -> () -> () : @DispatchCall.DerivedCallClass.OcCall() -> () [override] // DerivedCallClass.OcCall()

}

四、動態派發

1、調用代碼:

// FuncTest(object:)

sil hidden @DispatchCall.FuncTest(object: DispatchCall.BaseCallClass) -> () : $@convention(thin) (@guaranteed BaseCallClass) -> () {

// %0 // users: %7, %6, %5, %4, %3, %2, %1

bb0(%0 : $BaseCallClass):

debug_value %0 : $BaseCallClass, let, name "object", argno 1 // id: %1

%2 = class_method %0 : $BaseCallClass, #BaseCallClass.NormalCall!1 : (BaseCallClass) -> () -> (), $@convention(method) (@guaranteed BaseCallClass) -> () // user: %3

%3 = apply %2(%0) : $@convention(method) (@guaranteed BaseCallClass) -> ()

%4 = class_method %0 : $BaseCallClass, #BaseCallClass.OcCall!1 : (BaseCallClass) -> () -> (), $@convention(method) (@guaranteed BaseCallClass) -> () // user: %5

%5 = apply %4(%0) : $@convention(method) (@guaranteed BaseCallClass) -> ()

%6 = objc_method %0 : $BaseCallClass, #BaseCallClass.OcDynamicCall!1.foreign : (BaseCallClass) -> () -> (), $@convention(objc_method) (BaseCallClass) -> () // user: %7

%7 = apply %6(%0) : $@convention(objc_method) (BaseCallClass) -> ()

%8 = tuple () // user: %9

return %8 : $() // id: %9

} // end sil function ‘DispatchCall.FuncTest(object: DispatchCall.BaseCallClass) -> ()‘

2、虛函數表中的函數派發:

通過class_method(類的實例變量、函數名稱)的形式查找虛函數表到具體的函數;

然後apply執行;先將函數綁定到類實例,得到方法;然後調用方法執行;

3、oc的動態派發

sil提供了對swift方法的統一實現提供了兩個實現:oc可見實現和swift具體功能實現;同時將oc可見實現構造進oc的派發列表中;

派發列表的搜索和oc原生的搜索一致;先搜索子類的實現,沒有再搜索父類的實現;

提供給oc派發列表的函數是一個中間函數,這個函數與具體實現的函數一一對應,並實現了對具體函數的調用;

先通過objc_method(類的實例變量、函數名稱)查找派發列表得到chunk函數;chunk函數與函數的具體實現一一對應;

然後調用chunk函數;

chunk函數內部調用函數的具體實現;

// DerivedCallClass.OcDynamicCall()

sil hidden @DispatchCall.DerivedCallClass.OcDynamicCall() -> () : $@convention(method) (@guaranteed DerivedCallClass) -> () {

// %0 // user: %1

bb0(%0 : $DerivedCallClass):

debug_value %0 : $DerivedCallClass, let, name "self", argno 1 // id: %1

%2 = tuple () // user: %3

return %2 : $() // id: %3

} // end sil function ‘DispatchCall.DerivedCallClass.OcDynamicCall() -> ()‘

// @objc DerivedCallClass.OcDynamicCall()

sil hidden [thunk] @@objc DispatchCall.DerivedCallClass.OcDynamicCall() -> () : $@convention(objc_method) (DerivedCallClass) -> () {

// %0 // users: %4, %3, %1

bb0(%0 : $DerivedCallClass):

strong_retain %0 : $DerivedCallClass // id: %1

// function_ref DerivedCallClass.OcDynamicCall()

%2 = function_ref @DispatchCall.DerivedCallClass.OcDynamicCall() -> () : $@convention(method) (@guaranteed DerivedCallClass) -> () // user: %3

%3 = apply %2(%0) : $@convention(method) (@guaranteed DerivedCallClass) -> () // user: %5

strong_release %0 : $DerivedCallClass // id: %4

return %3 : $() // id: %5

} // end sil function ‘@objc DispatchCall.DerivedCallClass.OcDynamicCall() -> ()‘

五、第三方解釋chunk:

chunk只是包殼,功能有二:1、oc繼承體系中派發列表可見;2、消息轉發給具體的實現;

The magic bit of glue here is a thunk. In the Swift to Objective-C world, this is an additional method callable from Objective-C. It’s a thin wrapper and all it needs to do is call through to the native Swift method.

https://swiftunboxed.com/interop/objc-dynamic/

swift class的動態派發