Swift isa指针重映射或其他支持的方法调配

Jas*_*ues 12 objective-c objective-c-runtime swift

Swift类是否具有可以重新映射的isa指针?

我们已经看到Swift 使用比Objective-C 更静态的方法调度,它(除非来自Foundation/NSObject的类设备)在运行时基于重映射方法实现防止了调配风格.

我想知道我们将如何实现基于方法拦截的动态功能,如观察者模式,通知等?目前所有这些东西都是由Objective-C层提供的,可以很容易地集成到Swift中.但是,如果我们想在我们自己的框架(或应用程序)中提供这些类型的功能,是否有必要在Objective-C中实现它们?我认为有一种方法可以"原生"地完成它.

另一种对Objective-C来说很常见的混合是重新映射isa-pointer来动态生成一个子类.Swift是否支持这种调配?如果没有什么拦截任意的方法调用的支持呢?

编辑: 正如@jatoben指出的那样,从arm64开始重新映射必须通过调用object_setClass()而不是直接访问该值来完成.这仍然被称为'isa指针调配'

Jas*_*ues 11

看起来像方法交换和isa指针重新映射技术只有在Swift类将NSObject作为超类(直接或进一步向上)时才有效.当Swift类没有超类或其他非基础类时,它当前不起作用.

以下测试显示了这一点:

类:小鸟

class Birdy: NSObject {    
    func sayHello()
    {
        println("tweet tweet")
    }    
}
Run Code Online (Sandbox Code Playgroud)

分类:HodorBirdy

class HodorBirdy: Birdy {

    override func sayHello()
    {
        super.sayHello()
        println("hodor hodor")
    }
}
Run Code Online (Sandbox Code Playgroud)

测试:

func testExample() {        
    var birdy : Birdy = Birdy()
    object_setClass(birdy, HodorBirdy.self)
    birdy.sayHello();
}
Run Code Online (Sandbox Code Playgroud)

产量如预期:

tweet tweet
hodor hodor
Run Code Online (Sandbox Code Playgroud)

在此测试中,基类和子类都是事先创建的.虽然它们也可以使用Objective-C运行时动态创建,只要该类具有NSObject作为祖先.

当Swift类不是从Objective-C基础派生的时候,那么编译器将支持基于静态或基于vtable的调度,因此在这种情况下,它不清楚方法拦截将如何工作!

除非语言/编译器对它做出特定的限制,否则我们将会有利于性能的动力.(拦截,这是'动态'行为的基础,可以在编译时或运行时完成.对于没有虚拟机的静态或vtable-dispatch,只应用编译时).