美文网首页
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