一、思考
- alloc 到底做了什么事?
- init 有什么用?
- [[Class alloc] init] 与 new有什么区别?
通过这段代码,我们可以看出p1、p2、p3的指针地址虽然不同,但是指向的对象却是同一个,也就是同一片内存空间。
+ (instancetype)alloc OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
二、alloc源码分析
准备工作
1.从 苹果官方开源代码列表 找到 objc4
源码,但是这个源码是不可以编译的,需要编译的源码可在这里下载、配置源码可编译调试可参考这里
2.进入alloc方法可看到:
+ (id)alloc {
return _objc_rootAlloc(self);
}
3.跟踪代码,调用方法如下:
方法调用.png
4.具体分析_class_createInstanceFromZone方法
_class_createInstanceFromZone.png
5.因此,我们就可以确定alloc至少做了两件事:
6.没属性的对象为什么会占用内存?
每个对象都有一个隐藏属性isa 每个指针占8个字节---目前系统分配空间是以16字节为单位,通过字节对齐。一个对象只有isa指针也会占16个字节
具体的内存对齐原则的相关描述可以查看:iOS内存对齐原则
需要注意的是目前采用的是16字节对齐
三、既然alloc将开辟内存关联类型都做了,那么init又是在干嘛呢?
1.定位代码:
- (id)init {
return _objc_rootInit(self);
}
_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;
}
四、那么new 与[[Class alloc] init] 有什么区别呢?
1.定位代码
+ (id)new {
return [callAlloc(self, false/*checkNil*/) init];
}
callAlloc(Class cls, bool checkNil, bool allocWithZone=false) //new 使用默认参数
{
#if __OBJC2__
if (slowpath(checkNil && !cls)) return nil;
if (fastpath(!cls->ISA()->hasCustomAWZ())) {
return _objc_rootAllocWithZone(cls, nil);
}
#endif
// No shortcuts available.
if (allocWithZone) {
return ((id(*)(id, SEL, struct _NSZone *))objc_msgSend)(cls, @selector(allocWithZone:), nil);
}
return ((id(*)(id, SEL))objc_msgSend)(cls, @selector(alloc));
}
// Base class implementation of +alloc. cls is not nil.
// Calls [cls allocWithZone:nil].
id
_objc_rootAlloc(Class cls)
{
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);//alloc的参数allocWithZone为true
}
2.可见new和[[Class alloc] init],唯一区别就是allocWithZone参数为false
iOS 中 alloc init 和new的区别
扩展一、fastpath 和 slowpath
#define fastpath(x) (__builtin_expect(bool(x), 1))
#define slowpath(x) (__builtin_expect(bool(x), 0))
__builtin_expect(exp, n) 方法表示 exp 很有可能为 0,返回值为 exp。
fastpath意思是:bool(x)为真的概率很大
slowpath意思是: bool(x)为真的概率很小
首先要明确:
if(fastpath(value)) //等价于 if(value)
if(slowpath(value)) //也等价于 if(value)
也就是说,使用fastpath(),执行 if 后面的语句的机会更大,使用 slowpath(),执行 else 后面的语句的机会更大。通过这种方式,编译器在编译过程中,会将可能性更大的代码紧跟着起面的代码,从而减少指令跳转带来的性能上的下降。
其实将fastpath和slowpath去掉是完全不影响任何功能的。之所以将fastpath和slowpath 放到if语句中,是为了告诉编译器,if中的条件是大概率(fastpath)还是小概率(slowpath)事件,从而让编译器对代码进行优化。参考
扩展二、[[NSObject alloc] init]和[[LGPerson alloc] init]差异
NSObject *objc1 = [[NSObject alloc] init];
方法调用如下:
// Calls [[cls alloc] init].
id
objc_alloc_init(Class cls)
{
return [callAlloc(cls, true/*checkNil*/, false/*allocWithZone*/) init];
}
LGPerson *objc2 = [[LGPerson alloc] init];
方法调用如下:
// Calls [[cls alloc] init].
id
objc_alloc_init(Class cls)
{
return [callAlloc(cls, true/*checkNil*/, false/*allocWithZone*/) init];
}
+ (id)alloc {
return _objc_rootAlloc(self);
}
// Base class implementation of +alloc. cls is not nil.
// Calls [cls allocWithZone:nil].
id
_objc_rootAlloc(Class cls)
{
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
然后调用
- (id)init {
return _objc_rootInit(self);
}
流程图如下:
WX20200905-215003.png具体流程图如下:
1616482-20d480c0d97b38b9.png
流程图参考:陪妮走未来
网友评论