由于正常途径下我们能看到的alloc方法有限,要研究它的底层实现,我们需要先获取到objc的底层源码.
objc源码可以通过苹果opensource网站获取:
opensource.apple.com/source/objc…
源码的编译参考Coici老师的文章 juejin.cn/post/684490… 来探究OC方法的底层实现.
alloc 方法
alloc是我们最常见的方法,那么我们使用alloc方法主要是做了什么呢?主要就是用来开辟内存空间,我们通过如下方法来看一下:
可以发现p1,p2,p3都指向了相同的地址空间,也就是说主要是alloc方法开辟了内存空间,init方法并没没有新开辟内存空间,接下来我们再来看一下alloc方法是如何来开辟和分配内存空间的:
通过下载objc源码以及源码编译器调试,可以发现alloc内部的方法调用顺序是:
alloc -> _objc_rootAlloc -> callAlloc -> _objc_rootAllocWithZone -> _class_createInstanceFromZone 或者 alloc -> _objc_rootAlloc -> callAlloc -> objc_msgSend
负责内存开辟与分配的主要是方法 _class_createInstanceFromZone
苹果内存地址最新版本采用的是16字节对齐方式:
static inline size_t align16(size_t x) { return (x + size_t(15)) & ~size_t(15);}
- size = cls->instanceSize(extraBytes),这个方法的作用是计算出需要的内存空间大小
2) obj = (id)calloc(1, size) 这个方法就是去开辟size大小的内存区域,返回指向obj这块内存的指针.
- obj->initInstanceIsa(cls, hasCxxDtor),该方法的作用是将开辟的内存关联到相应类.
init方法
- (id)init { return _objc_rootInit(self);
}
id_objc_rootInit(id obj){ // In practice, it will be hard to rely on this function. // Many classes do not properly chain -init calls.
return obj;
}
可以看到,init方法只是返回了alloc得到的obj地址,所以开始的示例中,p1、p2、p3指向的指针都是相同的.
new方法
+ (id)new { return [callAlloc(self, false/*checkNil*/) init];}
new方法调用了callAlloc方法,这只是上面alloc方法调用步骤中的一个,所以new是不能等同于alloc的,不建议直接调用new方法,主要原因是它没有办法调用重写自定义的init方法.
new 方法实现原理:
//1,给对象分配内存空间地址
//2,给对象完成默认的初始化操作
//3,返回对象空间地址给对象指针