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 Answers
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.
1 Comment
#define FAST_IS_SWIFT_LEGACY (1UL<<0) and #define FAST_IS_SWIFT_STABLE (1UL<<1).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 Comment
A.B.
NSObjectin Objective-C. Some classes can have a root class ofNSProxy(though this isn't very common).