1. 用到的软硬件
- Macbook Air
- macOS Mojave 10.15.6
- Xcode 11.3.1
- Object-C(编程语言)
2. 新建一个项目
- objc4-781源码 https://pan.baidu.com/s/1h33XksmvMAvmojxgTWKi9Q 提取码: cfei
3. OC中的类是什么
首先我们要了解oc和c/c++
有什么关系,准确的说oc
和c
有什么关系。这可能要扯到历史,oc
和c++
没有半毛钱的关系,oc
是c
的面向对象的扩展。计算机语言发展简史。
首先我们通过苹果开源最新一期源码objc4-781中可以得知,类的实例化中做到开辟内存空间 (id)calloc(1, size)和关联相应的类 obj->initInstanceIsa(cls, hasCxxDtor)
这里的cls在源码里的定义,可以看出oc中的类是结构体指针对象。
typedef struct objc_class *Class;
typedef struct objc_object *id;
4. OC中的类 元类 根元类
通过上面我们可以知道oc中的类是一个objc_class
并且它还继承了一个objc_object
的结构体(这里存放了一个isa
)
struct objc_class : objc_object {
// 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
class_rw_t *data() const {
return bits.data();
}
void setData(class_rw_t *newData) {
bits.setData(newData);
}
void setInfo(uint32_t set) {
ASSERT(isFuture() || isRealized());
data()->setFlags(set);
}
....
....
....
}
那么isa
是什么?
一个对象被创建总是要有一个isa
并且占用内存中的第一个位置
if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# define ISA_MAGIC_MASK 0x000003f000000001ULL
# define ISA_MAGIC_VALUE 0x000001a000000001ULL
# define ISA_BITFIELD \
uintptr_t nonpointer : 1; \
uintptr_t has_assoc : 1; \
uintptr_t has_cxx_dtor : 1; \
uintptr_t shiftcls : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
uintptr_t magic : 6; \
uintptr_t weakly_referenced : 1; \
uintptr_t deallocating : 1; \
uintptr_t has_sidetable_rc : 1; \
uintptr_t extra_rc : 19
# define RC_ONE (1ULL<<45)
# define RC_HALF (1ULL<<18)
# elif __x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL
# define ISA_MAGIC_MASK 0x001f800000000001ULL
# define ISA_MAGIC_VALUE 0x001d800000000001ULL
# define ISA_BITFIELD \
uintptr_t nonpointer : 1; \
uintptr_t has_assoc : 1; \
uintptr_t has_cxx_dtor : 1; \
uintptr_t shiftcls : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
uintptr_t magic : 6; \
uintptr_t weakly_referenced : 1; \
uintptr_t deallocating : 1; \
uintptr_t has_sidetable_rc : 1; \
uintptr_t extra_rc : 8
# define RC_ONE (1ULL<<56)
# define RC_HALF (1ULL<<7)
这里的我们可以看出isa
是一个结构体位域
,这里面shiftcls
储存我们的类信息,打开我们的工程,新建一个Person类,实例化后打印它的内存地址,我们一起探究一下
Person *p = [Person alloc];
NSLog(@"%@",p);//断点
在lldb里面输出我们的p的内存信息(模拟器)
(lldb) x/4xg p
0x6000014a8870: 0x00000001005d54f8 0x0000000000000000
0x6000014a8880: 0x0000b0f092718880 0x00007fff87d0008a
(lldb) po 0x00000001005d54f8(这里是我们的类的isa)
Person
(lldb) p/x 0x00000001005d54f8 & 0x00007ffffffffff8ULL
(unsigned long long) $6 = 0x00000001005d54f8(这里得到shiftcls)
(lldb) po $6
Person
这里得到shiftcls
也是一个类,通过上面我们知道一个类由objc_class
创建出来,那么这里面也会有一个isa
,疑惑的我们再去通过lldb去看看这里的Person到底还有什么。
(lldb) x/4xg $6
0x1005d54f8: 0x00000001005d54d0 0x00007fff89e066c0
0x1005d5508: 0x00007fff514147b0 0x0000801000000000
(lldb) p/x 0x00000001005d54d0 & 0x00007ffffffffff8ULL
(unsigned long long) $7 = 0x00000001005d54d0
(lldb) po $7
Person
(lldb) x/4xg $7
0x1005d54d0: 0x00007fff89e06698 0x00007fff89e06698
0x1005d54e0: 0x00006000002af390 0x0003c03100000003
(lldb) p/x 0x00007fff89e06698 & 0x00007ffffffffff8ULL
(unsigned long long) $8 = 0x00007fff89e06698
(lldb) po $8
NSObject
(lldb) x/4xg $8
0x7fff89e06698: 0x00007fff89e06698 0x00007fff89e066c0
0x7fff89e066a8: 0x00007fc244d02610 0x0007c0310000000f
(lldb) p/x 0x00007fff89e06698 & 0x00007ffffffffff8ULL
(unsigned long long) $9 = 0x00007fff89e06698
(lldb) po $9
NSObject
通过上面我们就发现到了NSObjec
已经是最后一步了,给个这上面的流程图
这里就得到我们著名的isa流程图
5 lldb查看class_data_bits_t bits内容(可以不看)
补充内存偏移
int c[4] = {1,2,3,4};
int *d = c;
NSLog(@"%p - %p - %p",&c,&c[0],&c[1]);
NSLog(@"%p - %p - %p",d,d+1,d+2);
//0x7ffee6fff1b0 - 0x7ffee6fff1b4 - 0x7ffee6fff1b8
//0x7ffee6fff1b0 - 0x7ffee6fff1b4 - 0x7ffee6fff1b8
- 一个数组里面的首个内存地址和它的变量内存地址一样
- 后面偏移的内存位置为第一个内存地址+它前面出现元素的内存总和
为什么我们要查看class_data_bits_t bits的内容?
通过objc4源码可以得知bits里面有我们类创建的属性,方法,协议等等
struct objc_class : objc_object {
// Class ISA; 8字节
Class superclass; 8字节
cache_t cache; 16字节
class_data_bits_t bits;
class_rw_t *data() const {
return bits.data();
}
打开我们的objc4的源码,在我们的LGPerson.h里面添加2个成员变量
@interface LGPerson : NSObject{
NSString *name;
}
@property(nonatomic,strong)NSString *hobby;
@end
运行
(lldb) x/4gx p
0x100688240: 0x001d8001000021b5 0x0000000000000000
0x100688250: 0x0000000000000000 0x0000000000000000
(lldb) p/x 0x001d8001000021b5 & 0x00007ffffffffff8ULL
(unsigned long long) $1 = 0x00000001000021b0
通过上面知道我们的class_data_bits_t的内容存在
0x00000001000021b0 +(8+8+16) = 0x00000001000021d0
(lldb) x/4gx 0x00000001000021b0
0x1000021b0: 0x0000000100002188 0x00000001003f0140
0x1000021c0: 0x00000001006882c0 0x0001802400000003
(lldb) p (class_data_bits_t *)0x1000021d0
(class_data_bits_t *) $9 = 0x00000001000021d0
(lldb) p $9->data()
(class_rw_t *) $10 = 0x0000000100688280
(lldb) p *$10
(class_rw_t) $11 = {
flags = 2148007936
witness = 1
ro_or_rw_ext = {
std::__1::atomic = 4294975600
}
firstSubclass = nil
nextSiblingClass = NSUUID
}
这里得到我们的class_rw_t的内容,但是根本就没有看到我们的属性列表,这个时候通过objc4源码知道,它在我们的properties()里面
(lldb) p $11.properties()
(const property_array_t) $12 = {
list_array_tt = {
= {
list = 0x0000000100002150
arrayAndFlag = 4294975824
}
}
}
(lldb) p $12.list
(property_list_t *const) $13 = 0x0000000100002150
(lldb) p *$13
(property_list_t) $14 = {
entsize_list_tt = {
entsizeAndFlags = 16
count = 1
first = (name = "hoby", attributes = "T@\"NSString\",&,N,V_hoby")
}
}
6. 总结
- oc是c的面向对象的扩展
- oc中的类是结构体指针对象
- 关于类,元类,根元类的关系