https://tech.meituan.com/2015/03/03/diveintocategory.html
总结下来有几点:
1、Category中添加的方法,和本类中添加方法一样(实例方法在objc_class的methodList中)、(类方法在metaClass的methodList中)
问:那为什么Category的同名方法会“覆盖”本类的同名方法?
>答:并不是覆盖,而是重新添加了一次,调用等于方法寻址,找到地址低的那个方法,就调用了,
高的那个方法等于没用。
#问:如果有两个Category同时实现了同名方法,谁会被调用呢?
>答:要看compile Source的添加顺序,后添加的那个被调用
#问:两个Category都加了+(void)load方法,怎么调用呢
>答: 先类后category,而category的+load执行顺序是根据编译顺序决定的,先添加的那个先调用
2、Category中关联的对象(objc_setAssociatedObject、objc_getAssociatedObject)是怎么存储的呢?
这个问题,其实是问objc_setAssociatedObject添加的objc在哪里存储
答:程序启动的时候,会初始化一个AssociationsManager,它管理了一个static的AssociationsHashMap,这里面存储着所有对象关联的对象,这个map的key就是对象的指针,value是另外一个AssociationsHashMap,当对象销毁时,销毁对应的KV对。
3、这是个自己想到的问题,为什么不在预处理阶段,把category和本类合并,这样能添加成员变量、成员属性、成员方法?
这个问题,实际是说,为什么category是在运行期间决议的呢?
答:感觉:节省空间,对象大小取决于变量的多少,有的对象不用category中的属性,没必要为它开空间。比如你为NSObject声明几个category,并且set了几个变量,那么你整个工程中所有的对象,都大了一圈,所有只能是运行期间决议。
4、为什么category不能声明成员变量?
答:既然知道category是运行时期间动态为对象赋予的,那么就很好理解了。
OC的对象其实是个struct,大小由其成员变量多少决定,寻找变量也是通过首地址加偏移量的方式寻找对应的变量,而每个对象地址及大小都在编译阶段由对象对应的class定死了。如果声明变量,等于class的内存空间要增加,这样这个运行期的内存布局全乱套了,用官方的解释就是,这是灾难性的。
所有,由于category是运行期决议的,才是导致它不能声明变量的原因。
5、验证一点:
C++中用一个struct(也就是class),new一个对象,这个对象的大小是由struct中变量所占空间决定的,也就是每一个new出来的对象大小,是所有变量所占空间的和(这个结论是理论上的,因为可以能虚表等等),关键是和方法没关系,方法存在代码区,new出来的对象存在栈里面。所以结论是:成员变量和成员方法,不一样,每个对象都有自己的成员变量,但是所有对象共享成员方法。
比如:
```
MyClass * obj1 = [MyClass new];
obj1->int_a = 1;
[obj1 logName1];
MyClass * obj2 = [MyClass new];
obj2->int_a = 2;
[obj2 logName1];
```
然后再logName1方法中打印调用栈:
- (void)logName1{
NSLog(@"%@",[NSThread callStackSymbols]);
}
结果如下:发现调用logName1,都到到0x000000010f1b56cf这个地址
0 学习数据结构demo 0x000000010f1b56cf -[MyClass(abcd) logName1] + 47











网友评论