1.alloc 探索
创建一个NSObject对象 LGPerson
LGPerson *p1 = [LGPerson alloc];
LGPerson *p2 = [p1 init];
LGPerson *p3 = [p1 init];
LGNSLog(@"%@ - %p",p1,&p1);
LGNSLog(@"%@ - %p",p1,&p2);
LGNSLog(@"%@ - %p",p1,&p3);
控制台打印输出:
<LGPerson: 0x600002208560> - 0x7ffee9a44118
<LGPerson: 0x600002208560> - 0x7ffee9a44110
<LGPerson: 0x600002208560> - 0x7ffee9a44108
现象 :可以看到打印出来的三个对象是同一个
p1,p2,p3的指针地址是不同的 但是他们指向的是同一片内存地址
2.alloc是怎么创建的?具体实现原理探究
这里有三种方式来找
(1)下断点
通过 control + in 找到objec_alloc
(2) 通过下符号断点,如果事先知道方法,直接下
objc_alloc,或者直接下alloc断点
(3) 通过汇编方式
libobjc.A.dylib`objc_alloc:
3.通过源码分析流程
看源码 下载+配置
拿到源码,全局搜索alloc {,可以找到alloc方法,然后进入
_objc_rootAlloc方法,一步一步走。
通过源码分析可以看出流程
从上面的源码可以看出alloc方法开辟了内存,一个指针占用8个字节,这里提供里外一种二进制计算方式
// (x + WORD_MASK) >> 3 << 3
0000 1111 >> 3 0000 0001
0000 0001<<3 0000 1000 //8
对象需要内存空间 WORD_MASK 8的倍数 8字节对齐 同时if (size < 16) size = 16; 满足内存空间最小为16bytes
内存对齐:让CPU读取更加方便,用空间来换取时间
假设我们的内存快 字节方式补齐 如同4,5,6,7,8 读取就不方便
4.探索init,new方法
- (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出来的obj。
init没做任何操作,一般在这里是工厂方式来重写方法,自定义,我们经常会这样写代码
- (instancetype)init{
self = [super init];
if (self) {
}
return self;
}
//
[super init] 重写父类的方法 防止覆盖父类的方法
self = [super init]
= 是确认继承父类 可以延伸自己的方法
if(self)做判断处理 防止父类在init的时候return nil
做一个安全的处理 不然子类的实现就没有意义了
通过源码,看出new就是callAlloc+init的组合实现
+ (id)new {
return [callAlloc(self, false/*checkNil*/) init];
}