ISA走位
定义一个继承NSObject
的类ABPerson
,通过lldb
命令查看其ISA
的指向。
实例对象的ISA指向类对象
p/x p
打印实例对象p
的地址x/4gx 0x0000000100538ae0
打印该地址的内存,输出4段,首段存储着ISA
相关信息p/x 0x011d800100008185 & 0x00007ffffffffff8ULL
,通过约ISA_MASK
(0x00007ffffffffff8ULL)的&
操作,得到类对象ABPerson
po 0x0000000100008180
打印类对象
结论:实例对象的ISA指向类对象
类对象的ISA指向其元类
由上图可知0x0000000100008180
是类对象的地址,继续查看类对象的ISA
的指向:
能够看到得到了一个地址0x0000000100008158
,打印也是ABPerson
,这是就是元类,是由系统生成。类对象只有一个,可证明如下:
类对象ABPerson
的地址都是:0x100008190
。0x0000000100008158
是元类地址。
结论:类对象的ISA
指向其元类
元类的ISA指向根元类
由上图可知0x0000000100008158
是类的元类地址,继续查看元类的ISA
的指向:
能够看到元类的ISA
是指向NSObject
,也就是根元类。
结论:元类的ISA
是指向根元类
根元类的ISA指向其自身
由上图可知0x00007fff88967fe0
是根元类NSObject
的地址,继续查看根元类的ISA
的指向:
红框的地址都是相同的,都是其自身。
结论:根元类的ISA指向其自身
ISA走位图
继承链
定义一个子类ABTeacher
继承ABPerson
NSObject
的元类、根元类、根根元类都是0x7fff88967fe0
,是一个东西。ABPerson
是ABTeacher
是父类,ABTeacher
元类的父类地址是0x100008210
,ABPerson
的元类地址也是0x100008210
,所以ABTeacher
元类的父类就ABPerson
的元类。- 根类
NSObject
的父类为nil
- 根元类的父类地址是
0x7fff88968008
就是NSObject
最后附上苹果官方的的图
类的结构
objc
源码中查看Class
的定义:
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()