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

时间:2014-06-05 02:09:59

标签: objective-c swift objective-c-runtime

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

我们已经看到Swift uses a more static method dispatch而不是Objective-C(除非来自Foundation / NSObject的类设备)在运行时基于重映射方法实现阻止了混合风格。

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

另一种常见于Objective-C的混合是重新映射isa指针以动态生成子类。 Swift是否支持这种调配?如果不是 支持拦截任意方法调用的方式?

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

2 个答案:

答案 0 :(得分:11)

看起来方法交换和isa指针重新映射技术只有在Swift类将NSObject作为超类(直接或更高版本)时才有效。当Swift类没有超类或其他非基础类时,它当前不起作用。

以下测试显示:

上课:Birdy

class Birdy: NSObject {    
    func sayHello()
    {
        println("tweet tweet")
    }    
}

上课:HodorBirdy

class HodorBirdy: Birdy {

    override func sayHello()
    {
        super.sayHello()
        println("hodor hodor")
    }
}

<强>测试

func testExample() {        
    var birdy : Birdy = Birdy()
    object_setClass(birdy, HodorBirdy.self)
    birdy.sayHello();
}

输出结果符合预期:

tweet tweet
hodor hodor

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

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

除非语言/编译器对其作出特定的限制,否则我们将在动态上支持性能。 (拦截,这是动态行为的基础,可以在编译时或运行时完成。对于没有虚拟机的静态或vtable-dispatch,只有编译时适用)。

答案 1 :(得分:2)

我无法回答你关于swift&#34; isa&#34;的问题。相当于,但我想我知道你的基本问题的部分答案。

Property Observers 似乎是Observer Pattern的内置方法。而不是运行时发现&#34;类型&#34; (RTTI,有什么你)它是明确编织的。

来自&#39; Swift编程语言&#39;第345页:

  

财产观察员观察并回应财产的变化   值。每当物业的价值出现时,都会调用物业观察员   设置,即使新值与属性的当前值相同   值。

     

您可以将属性观察者添加到您定义的任何存储属性中,   除了懒惰的存储属性。您还可以添加属性观察器   通过覆盖任何继承的属性(无论是存储还是计算)   子类中的属性。

     

您可以选择在a上定义其中一个或两个观察者   属性:

     
      
  • 将在存储值之前调用willSet。
  •   存储新值后立即调用
  • didSet。
  •   

我不确定这一切是如何解决的,但我很感兴趣。

依赖于运行时类型发现似乎也与强静态类型正统相反。