Swift isa指针重新映射或其他受支持的方法 [英] Swift isa pointer remapping or other supported method swizzling

查看:230
本文介绍了Swift isa指针重新映射或其他受支持的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Do Swift classes have something like an isa pointer that can be remapped?

我们已经看到,Swift 使用的是比Objective-C更静态的方法分派,该方法(除非有类服务) (来自Foundation/NSObject)),可以防止基于运行时重新映射方法实现的混淆样式.

We've seen that Swift uses a more static method dispatch than objective-C, which (unless a class dervices from Foundation/NSObject) prevents the style of swizzling based on remapping method implementations at runtime.

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

I'm wondering how we'll implement method interception-based dynamic features like the observer pattern, notifications, etc? Currently all this stuff is provided by the Objective-C layer, and can be easily integrated into Swift. But, if we want to provide these kinds of features in a framework (or app) of our own, is it necessary to implement them in Objective-C? I would assume there's a way to do it 'natively'.

Objective-C常见的另一种麻烦是重新映射isa指针以动态生成子类. Swift是否支持这种麻烦?如果不是,则支持什么 拦截任意方法调用?

Another kind of swizzling common to objective-C is remapping the isa-pointer to generate a sub-class on the fly. Is this kind of swizzling supported in Swift? If not what is the supported way of intercepting arbitrary method invocations?

正如@jatoben指出的那样,从arm64开始,必须通过调用object_setClass()而不是直接访问该值来进行isa重映射.这仍称为"ISA指针混乱"

推荐答案

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

It looks like both method exchanging and the isa pointer remapping technique only works if the Swift class has NSObject as a super-class (either directly or further up). It does not currently work, when the Swift class has no super-class or some other non-Foundation base class.

以下测试显示了这一点:

The following test shows this:

班级:小鸟

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

班级:HodorBirdy

class HodorBirdy: Birdy {

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

测试:

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

输出与预期的一样:

tweet tweet
hodor hodor

在此测试中,基类和子类都是预先创建的.尽管也可以使用Objective-C运行时动态创建它们,只要该类将NSObject作为祖先即可.

In this test both the base-class and sub-class were created in advance. Though they could also be created dynamically using the Objective-C runtime as long as the class has NSObject as an ancestor.

当Swift类不是从Objective-C基础派生的时,编译器将倾向于基于静态或基于vtable的分派,因此,在这种情况下,方法截获完全是不清楚的!

When a Swift class does not derive from the Objective-C foundation, then the compiler will favor static- or vtable-based dispatch, therefore its not clear how method interception will work at all in this case!

除非语言/编译器对此有特别的规定,否则我们将放弃动态性以支持性能. (拦截是动态"行为的基础,可以在编译时或运行时进行.对于没有虚拟机的静态或vtable-dispatch,仅适用于编译时).

Unless the language/compiler make a specific allowance for it, we'll be foregoing dynamism in favor of performance. (Interception, which is the foundation of 'dynamic' behaviors can either be done at compile-time or run-time. In the case of static- or vtable-dispatch without a virtual machine, only compile-time applies).

这篇关于Swift isa指针重新映射或其他受支持的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆