定義一個繼承NSObject
的類ABPerson
,經過lldb
命令查看其ISA
的指向。git
p/x p
打印實例對象p
的地址x/4gx 0x0000000100538ae0
打印該地址的內存,輸出4段,首段存儲着ISA
相關信息p/x 0x011d800100008185 & 0x00007ffffffffff8ULL
,經過約ISA_MASK
(0x00007ffffffffff8ULL)的&
操做,獲得類對象ABPerson
po 0x0000000100008180
打印類對象結論:實例對象的ISA指向類對象github
由上圖可知0x0000000100008180
是類對象的地址,繼續查看類對象的ISA
的指向: 可以看到獲得了一個地址
0x0000000100008158
,打印也是ABPerson
,這是就是元類,是由系統生成。類對象只有一個,可證實以下:markdown
類對象
ABPerson
的地址都是:0x100008190
。0x0000000100008158
是元類地址。函數
結論:類對象的ISA
指向其元類oop
由上圖可知0x0000000100008158
是類的元類地址,繼續查看元類的ISA
的指向: 可以看到元類的
ISA
是指向NSObject
,也就是根元類。 結論:元類的ISA
是指向根元類佈局
由上圖可知0x00007fff88967fe0
是根元類NSObject
的地址,繼續查看根元類的ISA
的指向: 紅框的地址都是相同的,都是其自身。 結論:根元類的ISA指向其自身ui
定義一個子類ABTeacher
繼承ABPerson
atom
NSObject
的元類、根元類、根根元類都是0x7fff88967fe0
,是一個東西。ABPerson
是ABTeacher
是父類,ABTeacher
元類的父類地址是0x100008210
,ABPerson
的元類地址也是0x100008210
,因此ABTeacher
元類的父類就ABPerson
的元類。NSObject
的父類爲nil
0x7fff88968008
就是NSObject
最後附上蘋果官方的的圖 spa
objc
源碼中查看Class
的定義:debug
typedef struct objc_class *Class;
objc_class
的結構體定義:
struct objc_class : objc_object {
objc_class(const objc_class&) = delete;
objc_class(objc_class&&) = delete;
void operator=(const objc_class&) = delete;
void operator=(objc_class&&) = delete;
// 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
省略部分代碼
複製代碼
類的結構體佈局大概以下:
ISA
和superclass
都佔用一個結構體指針的大小8
字節cache
佔16
個字節,cache_t
結構體:struct cache_t {
private:
explicit_atomic<uintptr_t> _bucketsAndMaybeMask; // 8
union {
//聯合體互斥因此佔8
struct {
explicit_atomic<mask_t> _maybeMask; //uint32_t 4
#if __LP64__
uint16_t _flags; //uint16_t 2
#endif
uint16_t _occupied; //uint16_t 2
};
explicit_atomic<preopt_cache_t *> _originalPreoptCache; // 8
};
複製代碼
_bucketsAndMaybeMask
佔8
,當前union
佔8
,因此cache_t
佔16
若是想訪問bits
就須要內存平移8+8+16=32
個字節。
lldb調試:
調試工程下載
@interface LGPerson : NSObject
// isa
@property (nonatomic, copy) NSString *name;
@property (nonatomic) int age;
- (void)saySomething;
@end
複製代碼
x/4gx LGPerson.class
獲取類的首地址p/x 0x1000083a0 + 0x20
,首地址偏移32
個字節,拿到bits
p (class_data_bits_t *)0x00000001000083c0
,將地址強轉成class_data_bits_t
類型p $2->data()
,調用class_data_bits_t
中的data()
函數struct class_data_bits_t {
省略部分代碼
public:
class_rw_t* data() const {
return (class_rw_t *)(bits & FAST_DATA_MASK);
}
省略部分代碼
}
複製代碼
p $3->properties()
獲取類的屬性const property_array_t properties() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->properties;
} else {
return property_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProperties};
}
}
複製代碼
class property_array_t :
public list_array_tt<property_t, property_list_t, RawPtr>
{
typedef list_array_tt<property_t, property_list_t, RawPtr> Super;
public:
property_array_t() : Super() { }
property_array_t(property_list_t *l) : Super(l) { }
};
複製代碼
class list_array_tt {
struct array_t {
uint32_t count;
Ptr<List> lists[0];
static size_t byteSize(uint32_t count) {
return sizeof(array_t) + count*sizeof(lists[0]);
}
size_t byteSize() {
return byteSize(count);
}
};
省略部分代碼
}
複製代碼
property_array_t
繼承自list_array_tt
,list_array_tt
中有個結構體array_t
,結構體中有變量lists
p $4.list
拿到property_list_t
首地址p $5.ptr
打印property_list_t
首地址p *$6
取地址拿到property_list_t
p $7.get(0)
讀取property_list_t
中的成員變量p $3->methods()
獲取類的方法const method_array_t methods() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->methods;
} else {
return method_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseMethods()};
}
}
複製代碼
class method_array_t :
public list_array_tt<method_t, method_list_t, method_list_t_authed_ptr>
{
typedef list_array_tt<method_t, method_list_t, method_list_t_authed_ptr> Super;
public:
method_array_t() : Super() { }
method_array_t(method_list_t *l) : Super(l) { }
const method_list_t_authed_ptr<method_list_t> *beginCategoryMethodLists() const {
return beginLists();
}
const method_list_t_authed_ptr<method_list_t> *endCategoryMethodLists(Class cls) const;
};
複製代碼
class list_array_tt {
struct array_t {
uint32_t count;
Ptr<List> lists[0];
static size_t byteSize(uint32_t count) {
return sizeof(array_t) + count*sizeof(lists[0]);
}
size_t byteSize() {
return byteSize(count);
}
};
省略部分代碼
}
複製代碼
method_array_t
繼承自list_array_tt
,list_array_tt
中有個結構體array_t
,結構體中有變量lists
p $4.list
拿到method_list_t
首地址p $5.ptr
打印method_list_t
首地址p *$6
取地址拿到method_list_t
p $7.get(0).big()
讀取 method_list_t
中的實例方法struct property_t {
const char *name;
const char *attributes;
};
複製代碼
struct method_t {
static const uint32_t smallMethodListFlag = 0x80000000;
method_t(const method_t &other) = delete;
// The representation of a "big" method. This is the traditional
// representation of three pointers storing the selector, types
// and implementation.
struct big {
SEL name;
const char *types;
MethodListIMP imp;
};
省略部分代碼
}
複製代碼
對比結構體property_t
和method_t
可以看到,獲取屬性可直接$7.get(0)
拿到結構體,而method_t
裏面還有一個結構體big
,具體方法是放在big
裏面,因此要調用big()
。
修改LGPerson
代碼,添加一個成員變量,一個類方法
@interface LGPerson : NSObject
{
//成員變量
NSString *subject;
}
@property (nonatomic, copy) NSString *name;
@property (nonatomic) int age;
- (void)saySomething;
//類方法
+ (void)doSomething;
@end
複製代碼
@implementation LGPerson
- (void)saySomething{
NSLog(@"%s",__func__);
}
+ (void)doSomething{
NSLog(@"%s",__func__);
}
@end
複製代碼
- $3->ro()
,獲取class_ro_t
地址
const class_ro_t *ro() const {
auto v = get_ro_or_rwe();
if (slowpath(v.is<class_rw_ext_t *>())) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->ro;
}
return v.get<const class_ro_t *>(&ro_or_rw_ext);
}
複製代碼
p *$4
取地址,得到class_ro_t
p $5.ivars
獲取class_ro_t
的成員變量列表ivar_list_t
的首地址struct class_ro_t {
省略部分代碼
const ivar_list_t * ivars;
省略部分代碼
}
複製代碼
p *$6
取地址得到成員變量列表ivar_list_t
p $7.get(0)
打印成員變量x/4gx LGPerson.class
,打印LGPerson
的內存,獲得前8個字節0x00000001000083c0
p/x 0x00000001000083c0 & 0x00007ffffffffff8ULL
,得到元類地址ISA
走位:實例對象的ISA
指向類對象,類對象的ISA
指向其元類,元類的ISA
指向根元類,根元類的ISA
指向其自身nil
ISA
、superclass
、cache
、bits
32
位拿到class_data_bits_t
->data()
->properties()
->property_list_t
->get()
32``位拿到class_data_bits_t
->data()
->methods()
->method_list_t
->get().big()
32
位拿到class_data_bits_t
->data()
->ro()
->ivar_list_t
->get()
32``位拿到class_data_bits_t
->data()
->methods()
->method_list_t
->get().big()