美文网首页
了解alloc、Init 以及new方法

了解alloc、Init 以及new方法

作者: _涼城 | 来源:发表于2020-09-06 15:52 被阅读0次

在探索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];
}

相关文章

  • 了解alloc、Init 以及new方法

    在探索Alloc 与Init时,先输出两个对象的地址以及指向对象指针的地址,查看有什么区别。下面是一段Object...

  • 看透构造方法

    构造方法 new方法的内部就是先调用alloc方法,再调用init方法alloc方法:那个类接受alloc消息,那...

  • alloc init != new

    当我在做环信透传消息封装的时候,遇到了这个问题。 封装的类主要实现两个功能1:body构建,消息的构建,会话的构建...

  • alloc init and new

    1.在实际开发中很少会用到new,一般创建对象咱们看到的全是[[className alloc] init] 但是...

  • alloc init new

    alloc:分配内存。 init:初始化。 new:代替上面两个函数:分配内存,并且初始化。 注意: 1.在实际开...

  • alloc、init; new

    macOS Big Sur11.0.1Xcode 12.4objc4-818.2Apple Open Source...

  • IOS底层原理之isa

    在上一篇的文章深入底层理解alloc和init以及new中我们分析了alloc,知道了 alloc创建了对象并且分...

  • iOS 底层探索03-内存对齐

    在iOS 底层探索02-alloc/init/new 探索提到了alloc 流程中涉及的一个重要方法:instan...

  • init

    以 init 开始的方法的规则要比 alloc/new/copy/mutableCopy 更严格. 该方法必须是实...

  • iOS底层alloc & init & new方法

    通过一段代码开始分析alloc方法的本质: 分别输出3个对象的内容、内存地址、指针地址,下图是打印结果 通过打印结...

网友评论

      本文标题:了解alloc、Init 以及new方法

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