iOS-类的结构分析

774 阅读2分钟

1:isa 联合体(union)是互斥的,cls 与 bits 的初始化是互斥的。

类和元类的创建是在编译期。(验证:断点在main函数前,lldb打印 p/x、x/4xg打印类&元类的指针;machoView查看)

2:指针&内存偏移:

数组指针内存排布
普通指针 值拷贝 int a = 10 &a 为指针;对象:指针拷贝 不同的对象开辟的内存空间也不同 int *p = 10; p为指针;数组指针;

3:类的结构:objc_class *Class;
struct objc_class : objc_object;万物皆对象,类也是对象。

struct objc_class : objc_object {
    // Class ISA;           //8 byte
    Class superclass;       //8
    cache_t cache;          //16    // 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);
    }
    ......
}
struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;
#ifdef __LP64__
    uint32_t reserved;
#endif

    const uint8_t * ivarLayout;
    
    const char * name;
    method_list_t * baseMethodList;
    protocol_list_t * baseProtocols;
    const ivar_list_t * ivars;

    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;

    method_list_t *baseMethods() const {
        return baseMethodList;
    }
};
a sample:验证属性、方法在类里的存储。

LGTeacher *p = [LGTeacher alloc];
Class objct = object_getClass(p);

(lldb) p/x objct
(Class) $0 = 0x00000001000024e8 LGTeacher
(lldb) p (class_data_bits_t *)0x0000000100002508 
//根据内存的偏移,$0为LGTeacher首地址,偏移32(isa8 + supperclass8 + cache16)个字节为$1,
(class_data_bits_t *) $1 = 0x0000000100002508
(lldb) p $1->data()
(class_rw_t *) $2 = 0x000000010122f390
(lldb) p $2->ro
(const class_ro_t *) $3 = 0x0000000100002390
(lldb) p *$3
(const class_ro_t) $4 = {//存储着真实的类信息
  flags = 388
  instanceStart = 8
  instanceSize = 48
  reserved = 0
  ivarLayout = 0x0000000100001ecd "\x01\x11\x11"
  name = 0x0000000100001ec3 "LGTeacher"
  baseMethodList = 0x00000001000021a8
  baseProtocols = 0x0000000000000000
  ivars = 0x00000001000022a0
  weakIvarLayout = 0x0000000000000000
  baseProperties = 0x0000000100002348
}
(lldb) p $4.baseProperties
(property_list_t *const) $5 = 0x0000000100002348
(lldb) p *$5
(property_list_t) $6 = {
  entsize_list_tt<property_t, property_list_t, 0> = {
    entsizeAndFlags = 16
    count = 4
    first = (name = "name", attributes = "T@\"NSString\",C,N,V_name")
  }
}
(lldb) p $6.get(1)
(property_t) $7 = (name = "age", attributes = "Ti,N,V_age")
(lldb) p $6.get(2)
(property_t) $8 = (name = "height", attributes = "Tq,N,V_height")
(lldb) p $6.get(3)
(property_t) $9 = (name = "hobby", attributes = "T@\"NSString\",&,N,V_hobby")
(lldb) p *$4.baseMethodList//获取类的实例方法
(method_list_t) $10 = {
  entsize_list_tt<method_t, method_list_t, 3> = {
    entsizeAndFlags = 26
    count = 10
    first = {
      name = "sayHello"//自定义的实例方法,类方法不在此list
      types = 0x0000000100001f5f "v16@0:8"
      imp = 0x00000001000019b0 (LGTest`-[LGTeacher sayHello] at LGTeacher.m:13)
    }
  }
}

根据isa的走位图,同样可以找到 类方法的存储位置。