iOS-对象实例化alloc方法
栏目: Objective-C · 发布时间: 5年前
内容简介:写在最前:记录一个最近看到的一个问题,实例对象是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选中,
可以看到当前断点走到了23行(;分号表示说明,分号后面是说明内容)我们都知道,如果把[Person alloc]换成objc_msgSend的写法应该是objc_msgSend(Person,@selector(alloc)),我们看到第26行,(这里的bl相当于函数跳转,这一行指令就相当于在调用函数)接着在26行处打断点,我们通过寄存器来看一下,这个msgSend()的两个参数是什么?
(调用函数的时候,函数的参数是放在x0--x7这8个寄存器中的,关于寄存器的内容,我也只是浅层的了解,不好意思,后续会有补充) 现在我们可以知道26行的代码,其实就是在执行[Person alloc],下面我们alloc方法里下个符号断点,
之后过掉第26行的代码,
可以看到断点来到了NSObject alloc(当前Person类并没有重写alloc方法,肯定会来到其父类的alloc),可以看到这句代码调用的是_objc_rootAlloc,重复上一步,我们在下一个_objc_rootAlloc的符号断点,然后过掉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寄存器存放的是返回值,
可以看出此时x0存放的其实是Person对象的指针,接下来我们在第44行ret处添加断点,并过掉class_createInstance的断点,我们再来看一下寄存器x0存放的内容
然后po得到的这个地址,可以得到<Person: 0x1cc00d500>,此时返回的是一个person对象,此时此刻,一个完整的对象就创建完成了。所以说alloc才是真正创建实例对象的方法。
以上所述就是小编给大家介绍的《iOS-对象实例化alloc方法》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- OC对象的本质 实例对象,类对象,元类对象
- 面向对象-什么是类、实例化、对象、抽象类
- PHP 实例化对象注销
- 深入理解Objective-C中实例、类对象、元类对象之间的关系
- Stinger--实践实现特定实例对象的AOP
- [ PHP 内核与扩展开发系列] 类与面向对象:访问对象实例的属性和方法
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。