
image.png
- instance的isa指向class
當(dāng)調(diào)用對象方法時(shí),通過instance的isa找到class,最后找到對象方法的實(shí)現(xiàn)進(jìn)行調(diào)用 - class的isa指向meta-class
當(dāng)調(diào)用類方法時(shí),通過class的isa找到meta-class,最后找到類方法的實(shí)現(xiàn)進(jìn)行調(diào)用
class對象的superclass指針

image.png
當(dāng)Student的instance對象要調(diào)用Person的對象方法時(shí),會(huì)先通過isa找到Student的class,然后通過superclass找到Person的class,最后找到對象方法的實(shí)現(xiàn)進(jìn)行調(diào)用
meta-class對象的superclass指針

image.png
當(dāng)Student的class要調(diào)用Person的類方法時(shí),會(huì)先通過isa找到Student的meta-class,然后通過superclass找到Person的meta-class,最后找到類方法的實(shí)現(xiàn)進(jìn)行調(diào)用
isa、superclass總結(jié)
- instance的isa指向class
- class的isa指向meta-class
- meta-class的isa指向基類的meta-class
- class的superclass指向父類的class
如果沒有父類,superclass指針為nil - meta-class的superclass指向父類的meta-class
基類的meta-class的superclass指向基類的class - instance調(diào)用對象方法的軌跡
isa找到class,方法不存在,就通過superclass找父類 - class調(diào)用類方法的軌跡
isa找meta-class,方法不存在,就通過superclass找父類

image.png
從64bit開始,isa需要進(jìn)行一次位運(yùn)算,才能計(jì)算出真實(shí)地址,如下圖:

image.png
# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# elif __x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL

image.png
(lldb) p/x person->isa
(Class) $5 = 0x001d8001000014d1 LQPerson//isa指針的地址
(lldb) p/x 0x001d8001000014d1 & 0x00007ffffffffff8
(long) $6 = 0x00000001000014d0 //class對象的地址
struct objc_class的結(jié)構(gòu)

image.png
源碼中的定義如下:
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE;
const char * _Nonnull name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
class_rw_t *data() {
return bits.data();
}
void setData(class_rw_t *newData) {
bits.setData(newData);
}
......
struct class_rw_t {
// Be warned that Symbolication knows the layout of this structure.
uint32_t flags;
uint32_t version;
const class_ro_t *ro;
method_array_t methods;
property_array_t properties;
protocol_array_t protocols;
Class firstSubclass;
Class nextSiblingClass;
char *demangledName;
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
#ifdef __LP64__
uint32_t reserved;
#endif
const uint8_t * ivarLayout;
const char * name;
method_list_t * baseMethodList;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars;
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
method_list_t *baseMethods() const {
return baseMethodList;
}
};
ro--readonly
rw--readwrite
struct lq_objc_class {
Class isa;
Class superclass;
};
LQPerson *person = [[LQPerson alloc] init];
Class personClass = [LQPerson class];
打印結(jié)果如下:
(lldb) p/x person->isa
(Class) $0 = 0x001d8001000014c9 LQPerson
(lldb) p/x personClass
(Class) $1 = 0x00000001000014c8 LQPerson
(lldb) p/x 0x001d8001000014c9 & 0x0000000ffffffff8
(long) $2 = 0x00000001000014c8
由此可見,實(shí)例對象的的isa確實(shí)指向class對象
也可以通過如下方式驗(yàn)證superClass
(lldb) p/x studentClass->superclass
(Class) $3 = 0x00000001000014c8 LQPerson
QA
- 對象的isa指針指向哪里?
instance對象的isa指向class對象
class對象的isa指向meta-class對象
meta-class對象的isa指向基類的meta-class對象
- OC的類信息存放在哪里?
對象方法、屬性、成員變量、協(xié)議信息,存放在class對象中
類方法,存放在meta-class對象中
成員變量的具體值,存放在instance對象