This is an excerpt from Objective-C runtime programming guide
:
When a new object is created, memory for it is allocated, and its instance variables are initialized. First among the object’s variables is a pointer to its class structure. This pointer, called isa, gives the object access to its class and, through the class, to all the classes it inherits from.
isa is declared in NSObject
like this:
Class isa;
In its turn Class
is nothing more than a pointer to the struct
typedef struct objc_class *Class;
And now let's look at this structure:
struct objc_class {
Class isa;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
}
We can see that the pointer to the super class (as well as all the rest of the struct's members except another one isa) is unavailable in the latest version of Objective-C.
So my question is how an object can get access to its superclass if super_class
pointer is not available? Does it get access to the superclass through this another one isa pointer? But how exactly it happens? How it works? Can anyone explain it?
Even when written without a single line of Objective-C code, every Swift app executes inside the Objective-C runtime, opening up a world of dynamic dispatch and associated runtime manipulation.
Programming in Objective-C will not become obsolete any time soon because, thanks to its 20 years of existence, it has a large code base, a number of apps maintained, and third-party framework with Objective-C at its core. These solutions and libraries are unlikely to be rebuilt from scratch with a new language.
It won't be deprecated, but it'll move to Florida to enjoy its golden years. It'll spend days running the legacy app with a million lines of code, and its nights sipping margaritas with the OAuth library everyone fears rewriting.
just checked the source file
objc-class.m
Class class_getSuperclass(Class cls)
{
return _class_getSuperclass(cls);
}
runtime-new.mm
#define newcls(cls) ((class_t *)cls)
Class
_class_getSuperclass(Class cls)
{
return (Class)getSuperclass(newcls(cls));
}
static class_t *
getSuperclass(class_t *cls)
{
if (!cls) return NULL;
return cls->superclass;
}
so Class
is actually a pointer to class_t
objc-runtime-new.h
typedef struct class_t {
struct class_t *isa;
struct class_t *superclass;
Cache cache;
IMP *vtable;
uintptr_t data_NEVER_USE; // class_rw_t * plus custom rr/alloc flags
class_rw_t *data() const {
return (class_rw_t *)(data_NEVER_USE & ~(uintptr_t)3);
}
void setData(class_rw_t *newData) {
uintptr_t flags = (uintptr_t)data_NEVER_USE & (uintptr_t)3;
data_NEVER_USE = (uintptr_t)newData | flags;
}
bool hasCustomRR() const {
#if CLASS_FAST_FLAGS_VIA_RW_DATA
return data_NEVER_USE & (uintptr_t)1;
#else
return data()->flags & RW_HAS_CUSTOM_RR;
#endif
}
void setHasCustomRR(bool inherited = false);
bool hasCustomAWZ() const {
#if CLASS_FAST_FLAGS_VIA_RW_DATA
return data_NEVER_USE & (uintptr_t)2;
#else
return data()->flags & RW_HAS_CUSTOM_AWZ;
#endif
}
void setHasCustomAWZ(bool inherited = false);
bool isRootClass() const {
return superclass == NULL;
}
bool isRootMetaclass() const {
return isa == this;
}
} class_t;
and this is the struct that holds everything
anyway, these are internal implementation details and should not be relied on. so do not write code that rely on these because they may broken on next runtime update
dont rely on any internals of the class struct. -- you don't rely on other pals instance variables either! you look for properties
all you can safely do with the runtime is in runtime.h
for getting the superclass e.g.call class_getSuperclass
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With