透过现象看本质
作为一个流弊的程序猿,想要掌握一门语言,并且精通它,就必须扒开他的外衣,一层层往里看,研究他的内在(底层)原理。对于一个穿着鲜艳外衣的‘美女’,门外汉完全不知道怎么下手有咩有?
那我们到底应该怎么办呢?
好吧,我们只能从最熟悉的地方输入,比如说通过你的对象。如果你还没有对象,赶紧去开辟一个,或者申请一个吧。哈哈哈~~
首先我们来看下下面的代码。
1 | SCPerson *p1 = [SCPerson alloc]; |
看完上面的代码,我们来思考一下,你实际上到底拥有几个对象。
我们赶紧把他们的结果打印一下😏;
1 | <SCPerson: 0x600001c040e0> - 0x600001c040e0 - 0x7ffee9bee028 |
呦吼~~,p1,p2,p3
指针地址虽然不同,但是却指向了同一片内存空间。
这里就出现了非常经典的图
- 创建SCPerson时,申请开辟了内存空间
- p1, p2, p3 指向了同一片内存空间
原来init
只是一个构造函数,alloc
才是实干家,创建关联对象,开辟内存空间。alloc
做了这么多事情,它到底是怎么做到的呢?那我们就来扒开他的外衣,仔细进去看看吧。
===
揭露 alloc
的纱衣
我们想要知道 alloc
做了啥,第一步想到的肯定是 Jump to definition
, 通过她裸露的手臂,摸上去看一看。
1 | + (instancetype)alloc OBJC_SWIFT_UNAVAILABLE("use object initializers instead"); |
不给看。没关系我还有其他法宝,看我给你下个符号断点
- 我们下个
alloc
的符号断点
我们可以看到是调用了
libobjc.A.dylib
库的[NSObject alooc]
方法,并且jmp
跳转到_objc_rootAlloc
方法
- 我们再下
_objc_rootAlloc
符号断点
我们可以看到会调用
_objc_rootAllocZone
方法
- 啥样不说我们继续下
_objc_rootAllocZone
符号断点
通过一个个符号断点,我们能够大致知道 alloc
的基本流程
同样的除了这个办法我们还有其他方法,查看alloc
的基本流程
- 通过
ctrl step into
然后再下objc_alloc
符号断点Debug - Debug workflow - always show disassembly
查看汇编流程
但是无论如何,还是和汇编过不去,这样的操作,看的我这个流弊的程序猿头昏眼花。如果有个 能够跟流程的源码,那该有多少。这样美丽的对象
还不是随便让我扒了看?
谢天谢地,我这里竟然还有姑娘的房门钥匙:Objc4源码环境搭建, 嗨起来~
===
源码下的真容
拿到源码后,第一件事情肯定是 Jump to definition
, 终于我们可以看到美女袈裟下的面容了;
(这尼玛满文章的截图。。哈哈哈,好犹豫要不要Copy源码,算了先继续)
这里我们可以看到很多 fastpath
和 slowpath
他们又是什么呢?
1 |
苹果大婶们把大概率调用的方法定义了fastpath
,通过这种方式,编译器在编译过程中,会将可能性更大的代码紧跟着前面的代码,从而减少指令跳转带来的性能上的下降。这样 gcc
编译的指令会预先读取 fastpath
下的指令,系统运行时就会减少很多重新取值.
总结
通过源码我们可以看到 alloc
真正的流程是:
非常清晰有木有?后续我们将展开讲 cls->instanceSize
、calloc
、 initInstanceIsa
到底都做了什么?
感谢
通片文章由逻辑教育 Cooci老师大师班下的指导。不过现在是我的了~~