• 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) -> () : $@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/

  • 相关阅读:
    权限系统概要(收集,整理)
    全程参观 Google 总部
    从Excel表格中坐标生成 点线面
    Cross Site Script 知识
    UserControl 实现From_Close
    用后立即调用Dispose
    获取鼠标点击处的颜色
    arcsde9.3 the arcsde repository is not successfully created
    ArcGIS9.3全套 下载地址
    SQLServer 2008 安装 is not a volid login or don't have permission
  • 原文地址:https://www.cnblogs.com/feng9exe/p/10565979.html
Copyright © 2020-2023  润新知