1. iOS alloc&init
发布于 2022年 01月 14日 18:52
DHPerson *p1 = [DHPerson alloc];
DHPerson *p2 = [p1 init];
DHPerson *p3 = [p1 init];
NSLog(@"%@ - %p",p1,&p1);
NSLog(@"%@ - %p",p1,&p2);
NSLog(@"%@ - %p",p1,&p3);
打印如下
2019-12-28 16:58:32.125464+0800 001.allocinit[7025:169645] <DHPerson: 0x600001a78400> - 0x7ffee4fc5188
2019-12-28 16:58:32.125571+0800 001.allocinit[7025:169645] <DHPerson: 0x600001a78400> - 0x7ffee4fc5180
2019-12-28 16:58:32.125647+0800 001.allocinit[7025:169645] <DHPerson: 0x600001a78400> - 0x7ffee4fc5178
结论:P1、P2、P3三个不同的指针指向了同一块内存区域
那么alloc
init
到底做了什么呢?先找到相关的库(最好是真机调试),有3种方法:
1.alloc
行打断点,按住ctrl
+step into
进入
alloc
行打断点,Debug
--Debug Wolkflow
-- Always show Disassembly
显示汇编,ctrl
+step into
libobjc.A.dylib
这个动态库,下载objc
的源码opensource.apple.com/tarballs/ob…,并配置,最终得出alloc
流程图:
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,
bool cxxConstruct = true,
size_t *outAllocatedSize = nil)
alloc
方法主要是做申请开辟内存,并伴随初始化了一个属性isa(8个字节)
size_t instanceSize(size_t extraBytes) {
size_t size = alignedInstanceSize() + extraBytes;
// CF requires all objects be at least 16 bytes.
//最少16字节
if (size < 16) size = 16;
return size;
}
uint32_t alignedInstanceSize() {
return word_align(unalignedInstanceSize());
}
uint32_t unalignedInstanceSize() {
assert(isRealized());
return data()->ro->instanceSize;
}
//内存对齐:让CPU读取更加方便,用空间来换取时间
static inline uint32_t word_align(uint32_t x) {
// 7+8 = 15
// 0000 1111
// 0000 1000
//&
// 1111 1000 ~7
// 0000 1000 8
// 0000 0111
//
// x + 7
// 8
// 8 二阶
// (x + 7) >> 3 << 3
return (x + WORD_MASK) & ~WORD_MASK;
}
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;
}
这里补充一下alloc
首先会走objc_alloc
,因为在_read_images
的时候,发生了符号绑定sel_alloc
指向了objc_alloc
,这只走一次,如下图
init
返回的就是alloc出来的obj,验证了上面的打印结果p1,p2,p3都是同一个对象,也是为了方便开发人员能够在工厂设计开发的时候去扩展、自由定义
- (instancetype)init{
self = [super init];
if (self) {//做判断处理 防止父类在init的时候return nil
}
return self;
}
new函数
+ (id)new {
return [callAlloc(self, false/*checkNil*/) init];
}
new
基本等同于[[cls alloc] init]
,区别在于:
- new出的对象无法调用各种initWith...方法;
- alloc分配内存的时候使用了zone,这个zone它是给对象分配内存的时候,把关联的对象分配到一个相邻的内存区域内,以便于调用时消耗很少的代价,提升了程序处理速度。