swift class的动态派发

Posted feng9exe

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了swift class的动态派发相关的知识,希望对你有一定的参考价值。

一、测试代码

 

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) -> () : [email protected]onvention(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) -> () -> (), [email protected](method) (@guaranteed BaseCallClass) -> () // user: %3

  %3 = apply %2(%0) : [email protected](method) (@guaranteed BaseCallClass) -> ()

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

  %5 = apply %4(%0) : [email protected](method) (@guaranteed BaseCallClass) -> ()

  %6 = objc_method %0 : $BaseCallClass, #BaseCallClass.OcDynamicCall!1.foreign : (BaseCallClass) -> () -> (), [email protected](objc_method) (BaseCallClass) -> () // user: %7

  %7 = apply %6(%0) : [email protected](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() -> () : [email protected](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() -> () : [email protected](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() -> () : [email protected](method) (@guaranteed DerivedCallClass) -> () // user: %3

  %3 = apply %2(%0) : [email protected](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的动态派发的主要内容,如果未能解决你的问题,请参考以下文章

Swift 派发机制

swift protocol 见证容器 虚函数表 与 动态派发

Swift之从SIL深入分析函数的派发机制

swift @objc dynamic

iOS逆向之Swift汇编Protocol Witness Table初步认知

Swift