美文网首页
iOS 中的 alloc init和new的区别

iOS 中的 alloc init和new的区别

作者: kwdx | 来源:发表于2018-12-18 17:35 被阅读0次

在日常开发中,有的人会用[[Class alloc] init]创建实例,也有的人会用[Class new]的方式去创建实例。面试的时候,偶尔也会被问到这个问题。

那么,这两种方式创建出来的实例方法有什么区别呢?

本篇文章采用的源码是objc4-750.1版本

Source/NSObject.mm文件中可以找到alloc方法和new方法的实现

+ (id)new {
    return [callAlloc(self, false/*checkNil*/) init];
}

+ (id)alloc {
    return _objc_rootAlloc(self);
}

// Replaced by ObjectAlloc
+ (id)allocWithZone:(struct _NSZone *)zone {
    return _objc_rootAllocWithZone(self, (malloc_zone_t *)zone);
}

通过new方法创建的实例会调用init方法,那么[Class alloc] init][Class new]这两种方法的唯一区别就在于分配内存这一步,我们可以先找到_objc_rootAlloc的实现函数

// 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*/);
}

等等,callAlloc这个函数好熟悉啊,不就是new方法里面调用的函数吗?唯一的区别就是new方法调用的时候只传了2个参数,而_objc_rootAlloc这里传了3个参数,难道这两个函数不一样?还是说多出来的第3个参数有默认参数

// Call [cls alloc] or [cls allocWithZone:nil], with appropriate 
// shortcutting optimizations.
static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
    if (slowpath(checkNil && !cls)) return nil;

#if __OBJC2__
    if (fastpath(!cls->ISA()->hasCustomAWZ())) {
        // No alloc/allocWithZone implementation. Go straight to the allocator.
        // fixme store hasCustomAWZ in the non-meta class and 
        // add it to canAllocFast's summary
        if (fastpath(cls->canAllocFast())) {
            // No ctors, raw isa, etc. Go straight to the metal.
            bool dtor = cls->hasCxxDtor();
            id obj = (id)calloc(1, cls->bits.fastInstanceSize());
            if (slowpath(!obj)) return callBadAllocHandler(cls);
            obj->initInstanceIsa(cls, dtor);
            return obj;
        }
        else {
            // Has ctor or raw isa or something. Use the slower path.
            id obj = class_createInstance(cls, 0);
            if (slowpath(!obj)) return callBadAllocHandler(cls);
            return obj;
        }
    }
#endif

    // No shortcuts available.
    if (allocWithZone) return [cls allocWithZone:nil];
    return [cls alloc];
}

allocnew进来这个函数的差别就是allocWithZone参数了,从alloc那里的时候为truenew进来的时候为false;整个函数用到allocWihZone参数的地方就在于最后2行。

由于中间的东西涉及到OC中对象的本质内容,这里先不看,毕竟本文要探究的是allocnew的区别,所以忽略,有兴趣的可以自行阅读,主要对自定义allocallocWithZone类的处理。

言归正传,如果allocWithZone为真则会走[cls allocWithZone:nil],反之则走[cls alloc]

// 2019.4.1修改
从上面我们可以得知,通过[Class alloc]进入的最后会调[Class allocWithZone:nil]方法;而通过[Class new]方法最后则会调[Class alloc],然后再进入callAlloc去调用[Class allocWithZone:nil]
从上面我们可以得知,如果没有重写allocWithZone:方法,则[Class new]分配内存的方式和[Class alloc]分配方式是一样的,走fastpath(!cls->ISA()->hasCustomAWZ())里面的;而如果重写了allocWithZone:方法,则[Class new]会走到[Class alloc]方法

如果使用new的话,初始化方法就被固定只能调用init了,但如果用alloc init方式的话就不一定要用init了,还可以用initXXX等方法了。

总结

[Class new]就相当于调用[[Class alloc] init],一个为隐式调用,一个为显示调用而已。

打个小广告:Objective-C类Objective-C中的对象这两篇文章都有简单讲到OC对象本质。

相关文章

网友评论

      本文标题:iOS 中的 alloc init和new的区别

      本文链接:https://www.haomeiwen.com/subject/xjwlkqtx.html