定义一个继承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()