本页所使用的objc runtime 756.2,来自GITHUB
1. 题目
开始学习研究OC源码,今天看的是对象的初始化,也就是alloc以及init的分析。
2. 附流程图如下
3. 内容
3.1引子
我们先看一段代码,Person类的初始化,打印p1,p2,p3对象,以及指向他们的指针:
Person *p1 = [Person alloc]; |
打印结果是:
这里为什么p1相同的情况下,经过init后的p2,p3 的地址都不一样呢,我们要用这个图来分析:
在这里,我们**[Person alloc]创建了一个p 对象的内存空间,而[p1 init]**则是创建同样是指向p1的指针p2,p3,因为和p1 内存空间一致,所以地址均为0x6000024f4950,但是指向该3个指针的指针不一样,所以&p1, &p2, &p3 地址不一致。
3.2源码分析:
alloc 步骤如下
1. alloc
该步骤主要为创建对象,申请内存空间。相关objc源代码如下
+ (id)alloc { |
2. objc_rootAlloc
基类对于alloc 的实现,此时cls不为空,源码如下:
init方法:
类的init 如下
+(id)init{ |
对象的init如下
- (id)init{ |
id |
此处init 方法仅仅为工厂初始方法,作为父类方法,方便子类重写。
3. callAlloc**
callAlloc 的实现如下:
// Call [cls alloc] or [cls allocWithZone:nil], with appropriate |
4. class_createInstance
如上代码,如无捷径,类对象即创建实例
class_createInstance(Class cls, size_t extraBytes) |
5. _class_createINstanceFramZone
Cls->instanceSize
此时为对其寻址空间,统一为为每个对象开辟16位的位置,防止溢出。
size_t size = cls->instanceSize(extraBytes);
// CF requires all objects be at least 16 bytes.
if (outAllocatedSize) *outAllocatedSize = size;calloc
如果空间已开辟,则指定空间并返回,类似去学校报道,宿管阿姨带你去宿舍并交付钥匙给你,代码如下:
if (zone) {
// malloc_zone_calloc 即为开辟内存
obj = (id)malloc_zone_calloc ((malloc_zone_t *)zone, 1, size);
} else {
obj = (id)calloc(1, size);
}objc->initInstanceIsa
这一步为确定指针,即给宿舍贴上门牌号,相关代码如下:
if (!zone && fast) {
obj = (id)calloc(1, size); // 该行开辟了名为obj空间
if (!obj) return nil;
obj->initInstanceIsa(cls, hasCxxDtor);
}
在这一环节,obj = (id)calloc(1, size)
该行开辟了名为obj空间。
而obj->initInstanceIsa(cls, hasCxxDtor)
则真正的将内存空间obj 与类cls 进行关联上。
4. 总结
总的来说,alloc的过程,即时在堆区开辟空间给对象,并在栈区开辟指针(大小为8字节)指向该对象的内存区,即给定isa,以方便寻址。
以上,如果有更深入的理解,会再来补充,供参考。