iOS Detecting if a class is Objective-C or Swift

1.5k Views Asked by At

I'm working on an internal tool (something that will never be submitted to the App Store) and I'd like to detect at run time if a class is Objective-C or Swift. Is this possible?

2

There are 2 best solutions below

1
Brandon Schlenker On

Swift class names are prefixed with the name of the module. If one uses:

NSStringFromClass(SomeClass.self)

The result will be

MyApp.SomeClass

For my purpose, this works perfectly.

1
Richard J. Ross III On

If, for academic purposes, you absolutely must know if a class was created in swift code or not (and not in a way that can easily be fooled via objc_allocateClassPair), then you can utilize the information that can be found in objc-runtime-new.h, specifically, the flags related to FAST_IS_SWIFT.

To extract these flags without having to make your source code C++ or fight with including a ton of private headers, you can use something similar to the following, but please note: THIS IS SUPER FRAGILE.

This is probably not ABI-enforced anywhere, and any future version can change this without consequence. Bear that in mind, etc., etc.

Without further ado, the crazy hack ensues:

#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;
}

This is recreating the structure format from objc-runtime-new.h, without all of the additional C++ overhead.

Once you have the bits for a class, simply compare it it with FAST_IS_SWIFT (e.g. bits & FAST_IS_SWIFT), and you should have your answer.