前言:OC面向对象编程的,我们常常使用 alloc、init、new来把类实例化成对象,那么他们他们是如何工作的,以及他们之间有什么联系呢?
一.先看一段代码
NSObject *objc1 = [NSObject alloc];
NSObject *objc2 = [objc1 init];
NSObject *objc3 = [objc1 init];
NSLog(@"%@ - %p",objc1,&objc1);
NSLog(@"%@ - %p",objc2,&objc2);
NSLog(@"%@ - %p",objc3,&objc3);
输出:
InitViewController.m:(23): <NSObject: 0x600000a94be0> - 0x7ffee89358b8
InitViewController.m:(24): <NSObject: 0x600000a94be0> - 0x7ffee89358b0
InitViewController.m:(25): <NSObject: 0x600000a94be0> - 0x7ffee89358a8
由log可以看出objc1、objc2、objc3是由不同的指针指向同一块内存地址的
图示:
为什么会产生这样的结果呢?这还要从代码中找原因:
点击command + jump to alloc 发现跳到NSObjct.h中了
+ (instancetype)alloc OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
到这里就结束了,那我们要在哪里看alloc是如何实现的呢
二、3种断点方式
下面有三种打断点的方式,可以看见源码那那个库中
方法1:control + step into
objc_alloc: ->
libobjc.A.dylib`objc_alloc: ->
libobjc.A.dylib`_objc_rootAllocWithZone: ->
libsystem_malloc.dylib`calloc: -> ...
方法2:符号断点
位置:Debug->BreakPoints->Create Symbolic Breakpoint
符号 alloc 会出现 libobjc.A.dylib +[NSObject alloc]:
方法3: 查看汇编
位置:Debug->Debug Workflow->Always show Disassembly
断点,然后进入汇编 control + step in
会进入libobjc.A.dylib objc_alloc:
以上的三种方法都指向了同一个库libobjc.A.dylib
接下来让我们分析一下个库
三、源码分析
如何编译这个源码 在上一篇博客objc4-818.2源码 编译中写到
3.1.0 alloc实现原理
MMObject类什么都没有实现
#import <Foundation/Foundation.h>
#import "MMObject.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
MMObject *objc = [MMObject alloc];
}
return 0;
}
+ (id)alloc {
return _objc_rootAlloc(self);
}
id
_objc_rootAlloc(Class cls)
{
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
#if __OBJC2__
if (slowpath(checkNil && !cls)) return nil;
if (fastpath(!cls->ISA()->hasCustomAWZ())) {//没有实现 +allocWithZone
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));
}
id
_objc_rootAllocWithZone(Class cls, malloc_zone_t *zone __unused)
{
// allocWithZone under __OBJC2__ ignores the zone parameter
return _class_createInstanceFromZone(cls, 0, nil,
OBJECT_CONSTRUCT_CALL_BADALLOC);
}
static ALWAYS_INLINE id
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,
int construct_flags = OBJECT_CONSTRUCT_NONE,
bool cxxConstruct = true,
size_t *outAllocatedSize = nil)
{
ASSERT(cls->isRealized());
// Read class's info bits all at once for performance
bool hasCxxCtor = cxxConstruct && cls->hasCxxCtor();
bool hasCxxDtor = cls->hasCxxDtor();
bool fast = cls->canAllocNonpointer();
size_t size;
size = cls->instanceSize(extraBytes);// 计算需要开辟的内存大小 参数为0
if (outAllocatedSize) *outAllocatedSize = size;
id obj;
if (zone) {
obj = (id)malloc_zone_calloc((malloc_zone_t *)zone, 1, size);
} else {走这
obj = (id)calloc(1, size);//申请内存
}
if (slowpath(!obj)) {
if (construct_flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {
return _objc_callBadAllocHandler(cls);
}
return nil;
}
if (!zone && fast) {//走这
obj->initInstanceIsa(cls, hasCxxDtor);//将类与isa关联
} else {
// Use raw pointer isa on the assumption that they might be
// doing something weird with the zone or RR.
obj->initIsa(cls);
}
if (fastpath(!hasCxxCtor)) {//走这
return obj;//返回这个对象
}
construct_flags |= OBJECT_CONSTRUCT_FREE_ONFAILURE;
return object_cxxConstructFromClass(obj, cls, construct_flags);
}
这个是alloc的源码的过程
alloc -> _objc_rootAlloc -> callAlloc -> hasCustomAWZ() 没有实现+allocWithZone -> _objc_rootAllocWithZone -> _class_createInstanceFromZone 里面 申请内存calloc 将isa与类关联initInstanceIsa 返回 objc
3.1.1 MMObject类中实现了+allocWithZone
#import "MMObject.h"
@implementation MMObject
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
static id instance = nil;
@synchronized (self) {
if (instance == nil) {
instance = [super allocWithZone:zone];
}
}
return instance;
}
@end
前面都是一样的,hasCustomAWZ()会跳过去
static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
#if __OBJC2__
if (slowpath(checkNil && !cls)) return nil;
if (fastpath(!cls->ISA()->hasCustomAWZ())) {//不包含自定义的 +allocWithZone
return _objc_rootAllocWithZone(cls, nil);
}
#endif
// No shortcuts available. 没有使用快速创造方式
if (allocWithZone) {//走这里 因为实现了allocWithZone
return ((id(*)(id, SEL, struct _NSZone *))objc_msgSend)(cls, @selector(allocWithZone:), nil);
}
return ((id(*)(id, SEL))objc_msgSend)(cls, @selector(alloc));
}
3.2 init 的实现原理
MMObject *objc1 = [objc 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我们可以看见它什么都没有做,就返回了一个obj,那个这个有什么用呢,这是一种工厂设计模式,可以方便我们在初始化的时候可以做一些其他的操作。
3.2 new 的实现原理
MMObject *objc2 = [MMObject new];
+ (id)new {
return [callAlloc(self, false/*checkNil*/) init];
}
这句代码可以看见new调用了callAlloc参数默认false``allocWithZone=false,并且默认调用了init的方法。
总结
alloc开辟了内存空间,并且将类关联了isa指针
init什么都没有做,返回了原理的类
new相当于固化了实例化方式调用了init, [Class new]等价于[[Class alloc]init]