了解alloc、Init 以及new方法

在探索AllocInit时,先输出两个对象的地址以及指向对象指针的地址,查看有什么区别。下面是一段Objective-C的代码

  UIView  *p1 = [UIView alloc];
  UIView  *p2 = [UIView alloc];
  UIView  *p3 = [p1 init];
  UIView  *p4 = [p2 init];
  UIView  *p5 = [p2 init];
  NSLog(@"对象p1%@ - 指针地址%p",p1,&p1);
  NSLog(@"对象p2%@ - 指针地址%p",p2,&p2);
  NSLog(@"对象p3%@ - 指针地址%p",p3,&p3);
  NSLog(@"对象p4%@ - 指针地址%p",p4,&p4);
  NSLog(@"对象p5%@ - 指针地址%p",p5,&p5);

得到结果,可知P1 与 P3 指向地址空间相同, 指针地址不同;P2 与 P4、P5 指向地址空间相同,指针地址不同


截屏2020-09-06 下午2.46.50.png
如何查看alloc方法源码出处
通过添加断点进行查看
  1. 在代码处添加断点


    添加断点.png
  2. 按住ctrl键,点step按钮


    Step.png
  3. 查看系统函数objc_alloc

    ojbc_alloc.png

  4. 添加符号断点objc_alloc

    Symbol.png

  5. 找到对应库


    libobjc.A.dylib.png
alloc的流程

通过在objc源码 找到NSObject.mm中我们找到alloc方法的实现。

alloc

alloc类方法下,执行_objc_rootAlloc函数。

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

_objc_rootAlloc函数内,执行callAlloc函数

id
_objc_rootAlloc(Class cls)
{
    return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
callAlloc

通过符号断点调试,发现在callAlloc函数下执行objc-runtime-new.mm文件下的_objc_rootAllocWithZone函数。

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())) {
        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));
}


_objc_rootAllocWithZone

_objc_rootAllocWithZone ,执行_class_createInstanceFromZone函数

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);
}
_class_createInstanceFromZone(核心函数)
  1. 计算开辟空间的大小cls->instanceSize,(16字节对齐)
  2. 开辟内存空间calloc
  3. 将指针与类进行绑定obj->initInstanceIsa
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);
    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);
    } 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);
}
Init

Init方法

- (id)init {
    return _objc_rootInit(self);
}

_objc_rootInit函数

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返回的是它本身。

new

new函数中直接调用了callAlloc函数,且调用了init函数,所以可以得出new 其实就等价于 [alloc init]的结论。

+ (id)new {
    return [callAlloc(self, false/*checkNil*/) init];
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。