iOS检测类是Objective-C还是Swift

Bra*_*ker 2 objective-c objective-c-runtime swift

我正在研究一个内部工具(永远不会提交给App Store的东西),我想在运行时检测一个类是Objective-C还是Swift.这可能吗?

Ric*_*III 9

如果出于学术目的,你绝对必须知道一个类是否是用swift代码创建的(而不是以一种容易被愚弄的方式objc_allocateClassPair),那么你可以利用可以找到的信息objc-runtime-new.h,特别是标志与...有关FAST_IS_SWIFT.

要提取这些标志而不必使您的源代码C++或包含大量私有标题,您可以使用类似于以下内容,但请注意:这是超级易碎的.

这可能不是ABI强制执行的任何地方,任何未来的版本都可以改变这一点而不会产生任何后果.请记住等等.

没有进一步的麻烦,疯狂的黑客随之而来:

#define FAST_IS_SWIFT         (1UL<<0)
#define FAST_HAS_DEFAULT_RR   (1UL<<1)
#define FAST_DATA_MASK        0xfffffffcUL

uintptr_t getClassBits(Class kls) {
#if __LP64__
    typedef uint32_t mask_t;
#else
    typedef uint16_t mask_t;
#endif

    return ((const struct {
        /* struct objc_class */
        Class isa;
        Class superclass;

        /* struct cache_t */
        void *bucket_t;
        mask_t mask;
        mask_t occupied;

        /* struct class_data_bits_t */
        uintptr_t bits;
    } *) (__bridge const void *) kls)->bits;
}
Run Code Online (Sandbox Code Playgroud)

这是在objc-runtime-new.h没有所有额外的C++开销的情况下重新创建结构格式.

一旦你得到了一个类的位,只需将它与它FAST_IS_SWIFT(例如bits & FAST_IS_SWIFT)进行比较,你应该得到你的答案.

  • 实际上,新的ABI确实改变了这一点。标头现在定义了两个标志。#define FAST_IS_SWIFT_LEGACY(1UL &lt;&lt; 0)和#define FAST_IS_SWIFT_STABLE(1UL &lt;&lt; 1) (2认同)