final、dynamic、objc和_dynamicReplacement

优质
小牛编辑
130浏览
2023-12-01

final、dynamic、objc和_dynamicReplacement

结构体的方法是静态调用(直接调用), 方法默认不加任何修饰是通过sil-vtable函数表来进行调度

Object-C的分类方法会插入到类的方法表中, 而Swiftextension方法是静态调用(免去了Object-C插入扩展方法的异步操作, 理解为空间换取时间)

Swift继承, 子类会复制一份父类的方法到自己的方法表中,然后再编译自身的方法至方法表

  • final

    • final修饰符只能修饰类,表明该类不能被其他类继承,也就是它没资格当父类
    • final修饰符也可以修饰类中的属性、方法和下标,但前提是该类并没有被final修饰过
    • final不能修饰结构体和枚举
  • @objc

    标记暴露给Object-C, 不会修改方法的调度方式, 仍为直接/静态调用

    对编译器来说被修饰的方法会生成两个方法, 一个默认存在Swift类的方法表中, 另一个暴露给Object-C使用
    Object-C调用方法时, 会再调用swift定义的原有的方法

    @objc修饰后, 就可以通过runtime API获取对应的信息了, 如方法列表, 但如果需要给Object-C使用, 还需要继承自NSObject

  • dynamic

    dynamic修饰的方法有了动态特性, 依旧是方法表调用(直接/静态调用)

    允许被交换调用(@_dynamicReplacement(for: 方法名)), 类似于Object-C的运行时方法动态交换

  • @objc dynamic

    @objc dynamic修饰后, 会变成动态消息转发

  • @_dynamicReplacement

    Swift 5 Method Swizzling@_dynamicReplacement(for: 方法) 修饰方法, 参数for:后面就是将被替换的方法
    即调用方法时会调用被@_dynamicReplacement(for: 方法)修饰的方法

    注: @_dynamicReplacement关键字需要使用在extension


e.g. @_dynamicReplacement

class Person {

    dynamic func speechChinese() {
        print("speechChinese")
    }
}

extension Person {
    @_dynamicReplacement(for: speechChinese())
    func speechEnglish() {
        print("speechEnglish")
    }
}

let p = Person()
p.speechChinese() // 此时会调用 speechEnglish()

参考链接