类的结构是什么?
当问到类的本质是什么的时候,我们应该都知道是结构体。
下面我们就通过编译源码来看一下,类本质
我们创建一个类,
LGPerson *person = [LGPerson alloc]
Class pClass = object_getClass(person);
然后我们4gx打印pClass
接下来我们进行clang调试 我们OC代码被编译了这个样子,也是runtime的mesg
我们全局搜索LGPerson 可以看到LGPerson的具体是什么了,strut 结构体
我们想知道类的结构吗,所以我们需要继续查找 class 就是我们所说的类,这个源码可以很清楚的明白,class的真正类型是 objc_class
,objc_class 是什么
继承自objc_object
struct objc_class : objc_object {
// Class ISA; // 8
Class superclass; // 8
cache_t cache; // 16 不是8 // 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);
}
void setInfo(uint32_t set) {
assert(isFuture() || isRealized());
data()->setFlags(set);
}
void clearInfo(uint32_t clear) {
assert(isFuture() || isRealized());
data()->clearFlags(clear);
}
看这个结构内部含有一个class isa,注释了,说明这是个隐藏的类,所以isa 肯定是继承父类的 验证一下,jump 下就可以你看到.这个内部第一个是isa ,第二个就是superclass,第三个是cache,第四个是bit,这样我们就可以和4gx 打印的吻合了!我们po 出来的NSObject 就是父类
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;
但是这个被废弃了,我们继续查看
/// Represents an instance of a class.
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
NSObject 也是对这个仿写
属性和方法是存在哪里?
创建一个类,根据需要肯定会添加些属性,方法的,那么添加这些后会变成什么呢
之前已经确定了 0x001d800100002389 为isa指针,0x0000000100b37140为superclass,0x00000001003da260这里为cache_t,最后为bit,我们先读取bit里面有什么,需要使用地址偏移 isa 占8个字节,superclass占8个字节,chache_t 内部代码
struct cache_t {
struct bucket_t *_buckets; // 8
mask_t _mask; // 4
mask_t _occupied; // 4
所以chache_t 占16个字节,看下偏移结果
我们想看我们定义的属性在哪里,我们可以看见一个properties,那么久 p 下 发现了我们的属性,name 但是惊人的事情发生了,其实属性不在properlist里面,这个是个意外,其实是放在 ro 里面的!继续p
其实这个就是我们设置属性的Nickname
实例变量是放在ivas里的 p 下
实例变量和属性是有区别的,存储位置不同 name我们可以看到ivars 里面的count 为2 ,其实我们添加的属性,编译进来了,_nickName;
是不是想到了runtime copyivarlist 获取的属性为带下划线的*** 属性存在当前的类里面,并且就在bits里面 ***
方法在哪?
正好在p 属性的时候,可以看见methodlist,方法是否在这个里面?验证一下
确实是我们定义方法,但是数量是4,因为属性,系统会默认添加set,get方法,但是数量还是差一个,我们p 一下
可以看出多出的那一个为系统的c++方法, 但是我们还添加了一个类方法,只在这里看到了对象方法,类方法没有找到呢,这里是找不到了!我们尝试用代码获取方法列表void testIMP_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
IMP imp1 = class_getMethodImplementation(pClass, @selector(sayHello));
IMP imp2 = class_getMethodImplementation(metaClass, @selector(sayHello));
IMP imp3 = class_getMethodImplementation(pClass, @selector(sayHappy));
IMP imp4 = class_getMethodImplementation(metaClass, @selector(sayHappy));
NSLog(@"%p-%p-%p-%p",imp1,imp2,imp3,imp4);
NSLog(@"%s",__func__);
} 打印结果: 0x100002228-0x0-0x0-0x1000021c0