iOS NSObject源代码(1)alloc和init

来源:互联网 发布:log4net数据库 编辑:程序博客网 时间:2024/06/07 07:28

OC对象有四种状态:

(1)创建并持有对象:alloc init

(2)持有对象:retain、copy

(3)释放对象:release

(4)废弃对象:dealloc

1. alloc

首先看下alloc,这是从苹果官方源代码objc4/objc4-680/runtime/NSObject.mm提取出来的 点击打开链接
<span style="font-size:12px;">+ (id)alloc {    return _objc_rootAlloc(self);}</span>
<span style="font-size:12px;">// 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*/);}</span>

callAlloc的三个参数意思分别是cls:类信息(如NSString),checkNil:是否检查cls,allocWithZone:是否使用NSZone,如果直接调用alloc的话,系统会在默认的NSZone里面分配内存。


我们再来看看callAlloc的实现:

<span style="font-size:12px;">// Call [cls alloc] or [cls allocWithZone:nil], with appropriate // shortcutting optimizations.static ALWAYS_INLINE id  callAlloc(Class cls, bool checkNil, bool allocWithZone=false){    if (checkNil && !cls) return nil;#if __OBJC2__    if (! 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 (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 (!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 (!obj) return callBadAllocHandler(cls);            return obj;        }    }#endif    // No shortcuts available.    if (allocWithZone) return [cls allocWithZone:nil];    return [cls alloc];}</span>
首先先看看cls->ISA()->hasCustomAWZ(),源码在这
<span style="font-size:12px;">bool hasDefaultAWZ( ) {        return data()->flags & RW_HAS_DEFAULT_AWZ;    }</span>

RW_HAS_DEFAULT_AWZ 这个是用来标示当前的class或者是superclass是否有默认的alloc/allocWithZone。

所以这里hasDefaultAWZ( )方法是用来判断当前class是否有默认的allocWithZone。如果cls->ISA()->hasCustomAWZ()返回YES,意味着有默认的allocWithZone方法,那么就直接对class进行allocWithZone,申请内存空间。

if (! cls->ISA()->hasCustomAWZ()) { 

if (cls->canAllocFast())

这里这个类是否写好了快速分配的信息,因为跟allocWithZone同样调用了acalloc分配内存,不同的是后面的参数,所以个人感觉这里配置好分配内存的信不用在后面计算。

} else {

这里和allocWithZone里面的调用方法差不多

}

 }

先看看 [cls allocWithZone:zone] 这个吧

<span style="font-size:12px;">// Replaced by ObjectAlloc+ (id)allocWithZone:(struct _NSZone *)zone {   return _objc_rootAllocWithZone(self, (malloc_zone_t *)zone) }id _objc_rootAllocWithZone(Class cls, malloc_zone_t *zone){    id obj;#if __OBJC2__    // allocWithZone under __OBJC2__ ignores the zone parameter    (void)zone;    obj = class_createInstance(cls, 0);#else    if (!zone || UseGC) {        obj = class_createInstance(cls, 0);    }    else {        obj = class_createInstanceFromZone(cls, 0, zone);    }#endif    if (!obj) obj = callBadAllocHandler(cls);    return obj;}</span>

<span style="font-size:12px;">// 抛出异常static id defaultBadAllocHandler(Class cls){    _objc_fatal("attempt to allocate object of class '%s' failed",                 cls->nameForLogging());}static id(*badAllocHandler)(Class) = &defaultBadAllocHandler;static id callBadAllocHandler(Class cls){    // fixme add re-entrancy protection in case allocation fails inside handler    return (*badAllocHandler)(cls);}void _objc_setBadAllocHandler(id(*newHandler)(Class)){    badAllocHandler = newHandler;}</span>

可以看到#if __OBJC2__里面,iOS已经把NSZone区域给忽略了,所以NSZone内存分配方式已经不适用,之后我们再讨论iOS用哪种方式代替了。

创建OC对象都是用class_createInstance方法。

参考别人的资料,class_createInstance里面调用的class_createInstanceFromZone 点击打开链接

<span style="font-size:12px;">static __attribute__((always_inline))  id _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,                                bool cxxConstruct = true,                               size_t *outAllocatedSize = nil){    if (!cls) return nil;    assert(cls->isRealized());    // Read class's info bits all at once for performance    bool hasCxxCtor = cls->hasCxxCtor();    bool hasCxxDtor = cls->hasCxxDtor();    bool fast = cls->canAllocIndexed();    size_t size = cls->instanceSize(extraBytes);    if (outAllocatedSize) *outAllocatedSize = size;    id obj;    if (!UseGC  &&  !zone  &&  fast) {        obj = (id)calloc(1, size);        if (!obj) return nil;        obj->initInstanceIsa(cls, hasCxxDtor);    }     else {#if SUPPORT_GC        if (UseGC) {            obj = (id)auto_zone_allocate_object(gc_zone, size,                                                AUTO_OBJECT_SCANNED, 0, 1);        } else #endif        if (zone) {            obj = (id)malloc_zone_calloc ((malloc_zone_t *)zone, 1, size);        } else {            obj = (id)calloc(1, size);        }        if (!obj) return nil;        // Use non-indexed isa on the assumption that they might be         // doing something weird with the zone or RR.        obj->initIsa(cls);    }    if (cxxConstruct && hasCxxCtor) {        obj = _objc_constructOrFree(obj, cls);    }    return obj;}</span>
calloc( )函数会默认的把申请出来的空间初始化为0或者nil。

其中 垃圾回收器GC 也会使用gc_zone,个人猜测OC已经废弃了这个用法(和NSZone一样)


所以苹果alloc的基本实现过程:
(1)alloc
(2)allocWithZone
(3)class_createInstance
(4)calloc
(5)initIsa

2.init 

init的代码相对简单,只是需要返回self就可以了

<span style="font-size:12px;">// Replaced by CF (throws an NSException)+ (id)init {    return (id)self;}- (id)init {    return _objc_rootInit(self);}</span>
<span style="font-size:12px;"></span><pre>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;}


0 0
原创粉丝点击