zoukankan      html  css  js  c++  java
  • swift class的虚函数表、扩展、@objc修饰、虚函数的派发方式研究

    swift class的虚函数表、扩展、@objc修饰的研究

    工具:

    swiftc -emit-sil BaseClass.swift | xcrun swift-demangle > ClassFunc.silgen

    cat ClassFunc.silgen

    目标:

    1、@objc和@objc dynamic修饰的函数是否进入虚函数表;

    2、虚函数的的派发机制是什么?函数的调用在编译器层面最终转化为apply调用;

    3、extension中的缺省修饰函数是否进入虚函数表;

    4、extension中的@objc修饰函数的行为;

    5、结构体是否允许@objc修饰:

    @objc can only be used with members of classes, @objc protocols, and concrete extensions of classes

     

    https://www.cnblogs.com/feng9exe/p/9460336.html

    class NSObjectBase: NSObject {

        func Msg_Normal(){ print("Msg_Normal") }

        func Msg_Second(){ print("Msg_Second") }

        func Msg_Third(){ print("Msg_Second") }

        @objc func Msg_ObjcX(){}

        @objc dynamic func Msg_Objc_Dynamic(){}

        func callTest(){self.Msg_Normal()}

        func callAgain(){self.Msg_Third()}

    }

    extension NSObjectBase{

        @objc func OcExtensionFunc(){print("OcExtensionFunc")}

    }

    class DerivedOcClass:NSObjectBase{

        override func OcExtensionFunc(){print("DerivedOcClass OcExtensionFunc")}

    }

    // NSObjectBase.Msg_Objc_DynamicX()

    sil hidden @NSObjectBase.NSObjectBase.Msg_Objc_DynamicX() -> () : $@convention(method) (@guaranteed NSObjectBase) -> () {

    // %0                                             // user: %1

    bb0(%0 : $NSObjectBase):

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

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

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

    } // end sil function 'NSObjectBase.NSObjectBase.Msg_Objc_DynamicX() -> ()'

    // @objc NSObjectBase.Msg_Objc_DynamicX()

    sil hidden [thunk] @@objc NSObjectBase.NSObjectBase.Msg_Objc_DynamicX() -> () : $@convention(objc_method) (NSObjectBase) -> () {

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

    bb0(%0 : $NSObjectBase):

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

      // function_ref NSObjectBase.Msg_Objc_DynamicX()

      %2 = function_ref @NSObjectBase.NSObjectBase.Msg_Objc_DynamicX() -> () : $@convention(method) (@guaranteed NSObjectBase) -> () // user: %3

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

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

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

    } // end sil function '@objc NSObjectBase.NSObjectBase.Msg_Objc_DynamicX() -> ()'

    // NSObjectBase.Msg_ObjcX()

    sil hidden @NSObjectBase.NSObjectBase.Msg_ObjcX() -> () : $@convention(method) (@guaranteed NSObjectBase) -> () {

    // %0                                             // user: %1

    bb0(%0 : $NSObjectBase):

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

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

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

    } // end sil function 'NSObjectBase.NSObjectBase.Msg_ObjcX() -> ()'

    // @objc NSObjectBase.Msg_ObjcX()

    sil hidden [thunk] @@objc NSObjectBase.NSObjectBase.Msg_ObjcX() -> () : $@convention(objc_method) (NSObjectBase) -> () {

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

    bb0(%0 : $NSObjectBase):

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

      // function_ref NSObjectBase.Msg_ObjcX()

      %2 = function_ref @NSObjectBase.NSObjectBase.Msg_ObjcX() -> () : $@convention(method) (@guaranteed NSObjectBase) -> () // user: %3

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

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

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

    } // end sil function '@objc NSObjectBase.NSObjectBase.Msg_ObjcX() -> ()'

    sil hidden @NSObjectBase.NSObjectBase.callTest() -> () : $@convention(method) (@guaranteed NSObjectBase) -> () {

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

    bb0(%0 : $NSObjectBase):

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

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

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

      %4 = tuple ()                                   // user: %5

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

    } // end sil function 'NSObjectBase.NSObjectBase.callTest() -> ()'

    // NSObjectBase.callAgain()

    sil hidden @NSObjectBase.NSObjectBase.callAgain() -> () : $@convention(method) (@guaranteed NSObjectBase) -> () {

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

    bb0(%0 : $NSObjectBase):

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

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

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

      %4 = tuple ()                                   // user: %5

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

    } // end sil function 'NSObjectBase.NSObjectBase.callAgain() -> ()'

    sil_vtable NSObjectBase {

      #NSObjectBase.Msg_Normal!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.Msg_Normal() -> () // NSObjectBase.Msg_Normal()

      #NSObjectBase.Msg_Second!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.Msg_Second() -> () // NSObjectBase.Msg_Second()

      #NSObjectBase.Msg_Third!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.Msg_Third() -> ()// NSObjectBase.Msg_Third()

      #NSObjectBase.Msg_Objc!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.Msg_Objc() -> () // NSObjectBase.Msg_Objc()

      #NSObjectBase.callTest!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.callTest() -> () // NSObjectBase.callTest()

      #NSObjectBase.callAgain!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.callAgain() -> ()// NSObjectBase.callAgain()

    }

    sil_vtable DerivedOcClass {

      #NSObjectBase.Msg_Normal!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.Msg_Normal() -> () [inherited] // NSObjectBase.Msg_Normal()

      #NSObjectBase.Msg_Second!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.Msg_Second() -> () [inherited] // NSObjectBase.Msg_Second()

      #NSObjectBase.Msg_Third!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.Msg_Third() -> () [inherited] // NSObjectBase.Msg_Third()

      #NSObjectBase.Msg_Objc!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.Msg_Objc() -> () [inherited] // NSObjectBase.Msg_Objc()

      #NSObjectBase.callTest!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.callTest() -> () [inherited] // NSObjectBase.callTest()

      #NSObjectBase.callAgain!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.callAgain() -> () [inherited] // NSObjectBase.callAgain()

    apply担任函数绑定和派发的职责

    那么阅读就显得简单多了, 可以看到最终对应到 testFunc函数调用的指令有两条.

    %4 = class_method %2 : $MyClass, #MyClass.testFunc!1 : (MyClass) -> () -> (), $@convention(method) (@guaranteed MyClass) -> () // user: %5
    %5 = apply %4(%2) : $@convention(method) (@guaranteed MyClass) -> ()
    
    1. class_method: 该指令通过类的函数表来查找函数, 基于类的实际类型.
    2. apply: 传递参数并执行函数.


    作者:MaizeJS
    链接:https://www.jianshu.com/p/cfe7da01880d
    来源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
  • 相关阅读:
    MRC和ARC混合开发
    创建静态库.a
    IOS 数据存储之 FMDB 详解
    AFNETWorking的使用
    日历demo
    iOS开发系列--通知与消息机制
    paypal支付说明
    支付宝路径的问题
    iOS开发多线程篇—GCD介绍
    回调的具体最弱智的解释
  • 原文地址:https://www.cnblogs.com/feng9exe/p/10560753.html
Copyright © 2011-2022 走看看