iOS 类的结构

1,252 阅读3分钟

类的结构是什么?

当问到类的本质是什么的时候,我们应该都知道是结构体。

下面我们就通过编译源码来看一下,类本质

我们创建一个类,

    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

所以 对象方法在当前类返回了地址,类方法在元类返回了地址,所以类方法存在元类里面