iOS-对象实例化alloc方法

栏目: Objective-C · 发布时间: 7年前

内容简介:写在最前:记录一个最近看到的一个问题,实例对象是alloc创建的还是init创建的?写的不好,还请看到的人轻喷!有一个首先有两个疑问: Q1: p1和p2是相同的吗? Q2: p1.age和p2.age的值是多少?(0或者10) 我们先来看一下结果Q1:

写在最前:记录一个最近看到的一个问题,实例对象是alloc创建的还是init创建的?写的不好,还请看到的人轻喷!

有一个 Person 类,声明一个 age 属性

Person *p = [Person alloc];
    p.age = 10;
    Person *p1 = [p init];
    Person *p2 = [p init];
复制代码

首先有两个疑问: Q1: p1和p2是相同的吗? Q2: p1.age和p2.age的值是多少?(0或者10) 我们先来看一下结果Q1:

p1=<Person: 0x6000029bca80>
p2=<Person: 0x6000029bca80>
复制代码

通过其内存地址可以看到这两个对象是一样的(但是没存地址一样就足以证明这两个对象是同一个东西吗,这不一定,p1,p2在初始化的时候,初始化的内容可能不一样)

结果Q2:

p1.age=10
p2.age=10
复制代码

通过这个结果好像可以看出:

Person *p1 = [p init];
Person *p2 = [p init];

等价于

Person *p1 = p;
Person *p2 = p;

哦,似乎init方法没什么用啊?
复制代码

那我们就看一下alloc方法干了些什么 通过objc的NSObject代码:

1.
+ (id)alloc {
       reeturn _objc_rootAlloc(self);
}
可知返回的这个self应该就是指当前的这个类对象
2.在进一步跟进去_objc_rootAlloc
id
_objc_rootAlloc(Class cls)
{
       return callAlloc(cls, false/*chechNil*/, true/*allocWithZone*/);
}

3.跟进去callAlloc

static id callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
    if (checkNil && !cls) return nil;
    
    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 (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;
        }
    }
    
    // No shortcuts available.
    if (allocWithZone) return [cls allocWithZone:nil];
    return [cls alloc];
}
4.这里主要用到的代码就是id obj = class_createInstance(cls, 0);跟进去看到

id class_createInstance(Class cls, size_t extraBytes)
{
    return _class_createInstanceFromZone(cls, extraBytes, nil);
}
5.继续跟进去_class_createInstanceFromZone

static id _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone, 
                              bool cxxConstruct = true, 
                              size_t *outAllocatedSize = nil)
{
    if (!cls) return nil;// 首先是判断是否为空

    assert(cls->isRealized());// 检查是否已经realize 了

    // Read class's info bits all at once for performance
    bool hasCxxCtor = cls->hasCxxCtor();
    bool hasCxxDtor = cls->hasCxxDtor();
    bool fast = cls->canAllocNonpointer();

    size_t size = cls->instanceSize(extraBytes); // 这一步是获取对象大小的
    if (outAllocatedSize) *outAllocatedSize = size;
    id obj;
    if (!zone  &&  fast) {
        obj = (id)calloc(1, size); // 分配空间
        if (!obj) return nil;
        obj->initInstanceIsa(cls, hasCxxDtor);// 初始化
    } 
    else {
        if (zone) {
            obj = (id)malloc_zone_calloc ((malloc_zone_t *)zone, 1, size);
        } else {
            obj = (id)calloc(1, size);
        }
        if (!obj) return nil;

        // Use raw pointer 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;
}
最主要的代码就是
obj = (id)calloc(1, size);
if (!obj) return nil;
obj->initInstanceIsa(cls, hasCxxDtor);

复制代码

事实上我们看不到苹果的源码,下面通过汇编代码来看一下(真机调试),首先在Person *p = [Person alloc];处打个断点,当运行到该断点时,在Xcode菜单栏-->Debug-->DebugWorkflow-->Always Show Disassembly选中,

iOS-对象实例化alloc方法

可以看到当前断点走到了23行(;分号表示说明,分号后面是说明内容)我们都知道,如果把[Person alloc]换成objc_msgSend的写法应该是objc_msgSend(Person,@selector(alloc)),我们看到第26行,(这里的bl相当于函数跳转,这一行指令就相当于在调用函数)接着在26行处打断点,我们通过寄存器来看一下,这个msgSend()的两个参数是什么?

iOS-对象实例化alloc方法

(调用函数的时候,函数的参数是放在x0--x7这8个寄存器中的,关于寄存器的内容,我也只是浅层的了解,不好意思,后续会有补充) 现在我们可以知道26行的代码,其实就是在执行[Person alloc],下面我们alloc方法里下个符号断点,

iOS-对象实例化alloc方法
iOS-对象实例化alloc方法

之后过掉第26行的代码,

iOS-对象实例化alloc方法

可以看到断点来到了NSObject alloc(当前Person类并没有重写alloc方法,肯定会来到其父类的alloc),可以看到这句代码调用的是_objc_rootAlloc,重复上一步,我们在下一个_objc_rootAlloc的符号断点,然后过掉alloc的断点,

iOS-对象实例化alloc方法

可以看到rootAlloc第一次的函数调用时在第21行有函数跳转class_createInstance方法,同样的给class_createInstance添加一个符号断点,过掉_objc_rootAlloc的断点,[图片上传中...(屏幕快照 2019-04-25 下午10.41.03.png-dafb56-1556203291738-0)] 我们可以看到在第44行的ret(ret就相当于return),由前面我们知道调用函数的时候,函数的参数是放在x0--x7这8个寄存器中的,当函数调用完成之后,x0寄存器存放的是返回值,

iOS-对象实例化alloc方法

可以看出此时x0存放的其实是Person对象的指针,接下来我们在第44行ret处添加断点,并过掉class_createInstance的断点,我们再来看一下寄存器x0存放的内容

iOS-对象实例化alloc方法

然后po得到的这个地址,可以得到<Person: 0x1cc00d500>,此时返回的是一个person对象,此时此刻,一个完整的对象就创建完成了。所以说alloc才是真正创建实例对象的方法。


以上所述就是小编给大家介绍的《iOS-对象实例化alloc方法》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。

The Four

The Four

Scott Galloway / Portfolio / 2017-10-3 / USD 28.00

NEW YORK TIMES BESTSELLER USA TODAY BESTSELLER Amazon, Apple, Facebook, and Google are the four most influential companies on the planet. Just about everyone thinks they know how they got there.......一起来看看 《The Four》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

URL 编码/解码
URL 编码/解码

URL 编码/解码