1. iOS alloc&init

发布于 2022年 01月 14日 18:52

DHPerson *p1 = [DHPerson alloc];
DHPerson *p2 = [p1 init];
DHPerson *p3 = [p1 init];

NSLog(@"%@ - %p",p1,&p1);
NSLog(@"%@ - %p",p1,&p2);
NSLog(@"%@ - %p",p1,&p3);

打印如下

2019-12-28 16:58:32.125464+0800 001.allocinit[7025:169645] <DHPerson: 0x600001a78400> - 0x7ffee4fc5188
2019-12-28 16:58:32.125571+0800 001.allocinit[7025:169645] <DHPerson: 0x600001a78400> - 0x7ffee4fc5180
2019-12-28 16:58:32.125647+0800 001.allocinit[7025:169645] <DHPerson: 0x600001a78400> - 0x7ffee4fc5178

结论:P1、P2、P3三个不同的指针指向了同一块内存区域

那么alloc init到底做了什么呢?先找到相关的库(最好是真机调试),有3种方法:

1.alloc行打断点,按住ctrl+step into进入

2.打符号断点

3.alloc行打断点,Debug--Debug Wolkflow -- Always show Disassembly显示汇编,ctrl+step into

最终我们都定位到了libobjc.A.dylib这个动态库,下载objc的源码opensource.apple.com/tarballs/ob…,并配置,最终得出alloc流程图:
最终都会走向如下私有方法

_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone, 
                              bool cxxConstruct = true, 
                              size_t *outAllocatedSize = nil)

alloc方法主要是做申请开辟内存,并伴随初始化了一个属性isa(8个字节)

 size_t instanceSize(size_t extraBytes) {
        size_t size = alignedInstanceSize() + extraBytes;
        // CF requires all objects be at least 16 bytes.
        //最少16字节
        if (size < 16) size = 16;
        return size;
    }
uint32_t alignedInstanceSize() {
        return word_align(unalignedInstanceSize());
    }
uint32_t unalignedInstanceSize() {
        assert(isRealized());
        return data()->ro->instanceSize;
    }
//内存对齐:让CPU读取更加方便,用空间来换取时间
static inline uint32_t word_align(uint32_t x) {
    // 7+8 = 15
    // 0000 1111
    // 0000 1000
    //&
    // 1111 1000 ~7
    // 0000 1000 8
    
    // 0000 0111
    //
    // x + 7
    // 8
    // 8 二阶
    // (x + 7) >> 3 << 3
    return (x + WORD_MASK) & ~WORD_MASK;
}

init探索

- (id)init {
    return _objc_rootInit(self);
}
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;
}

这里补充一下alloc首先会走objc_alloc,因为在_read_images的时候,发生了符号绑定sel_alloc 指向了objc_alloc,这只走一次,如下图

init返回的就是alloc出来的obj,验证了上面的打印结果p1,p2,p3都是同一个对象,也是为了方便开发人员能够在工厂设计开发的时候去扩展、自由定义

- (instancetype)init{
    self = [super init];
    if (self) {//做判断处理 防止父类在init的时候return nil 
        
    }
    return self;
}

new函数

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

new基本等同于[[cls alloc] init],区别在于:

  1. new出的对象无法调用各种initWith...方法;
  2. alloc分配内存的时候使用了zone,这个zone它是给对象分配内存的时候,把关联的对象分配到一个相邻的内存区域内,以便于调用时消耗很少的代价,提升了程序处理速度。

推荐文章