Category

时间:2024-05-22 15:16:12

通过runtime动态添加的struct
Category
Category
Category
Category
Category

源码分析
重新组合方法
Category
Category
Category
Category
Category
Category

Category

Category
Category
Category
Category
Category
分类和类扩展有什么区别
类扩展是编译的时候就已经合并到类里面去了,相等于类扩展的东西一编译的时候就已经存在了,类扩展的作用本来是公开声明的东西放到.m文件中私有化,相等于变成一个私有的声明
而分类是程序运行机制,将分类数据合并到类信息中去.
Category
Cateogry-load
为什么调用类方法[MJPerson test]调用的是通过objc_msgSend([MJPerson test],@selector(test))就是给类对象发送一条test消息,发消息就是通过类对象的isa找到元类对象,找到元类对象里面的类方法列表按顺序遍历方法,遍历方法就是先找分类方法.父类方法就会被覆盖.
而load方法是通过这个方法在内存的地址直接找到的,所以load方法不会覆盖,一般不会主动调用Load方法,[MJPerson load]如果这样调用的话,也会走消息机制.
内存中一个结构体只存Load方法
Category
Category

调用顺序
如果没有父类,平级的话跟编译顺序有关,谁优先编译先加载load
Category
递归先调用父类
Category

总结
+load顺序
Category
Category
load方法之所以都调用是因为是直接通过函数指针,指向那个函数,拿到函数地址找到函数代码,直接掉用,分开调用.
* +initialize方法*
Category
Category
Category
这个不代表父类初始化三次,还是代表每个类初始化了一次,相等于第一句是person的初始化,第二句是student的初始化,第三次是teacher的初始化,只不过自己没有intialize就调用父类的intialize
Category
Category
Category
在分类中写属性,只能生成getter,setter方法的声明,并不能生成成员变量.也不能给getter,setter方法的实现
Category
这就是属性写在原来类和分类中的区别.
不能直接给Category添加成员变量.在Category中自己写成员实例变量会报错Instance variables may not be placed in categories.但可以间接实现.
利用关联对象实现 但是const void *MJNameKey如果不赋值的话,指针指向为NULL.后续就有问题,下图是指针指向自己本身的内存地址.
Category
因为全局变量const void *MJNameKey,想在外面访问
Category
可能从外面把里面的值改掉,改进一
Category
Category
这里MJNameKey不需要负值,因为我们要的是内存存储MJNameKey的地址值.
Category
改进

Category
这里的疑问是传进去的name和取出来的name是不是一样的,所以我们要知道,把@”name”传进去,是把name这个字符串的地址传进去,因为我们需要的是const void *,因为我们平时写字符串
NSString *str = @”name”;表示str装的这个”name”字符串的地址,所以质量吧@”name”放进去相当于吧str放进去
Category
打印发现地址是一样的
因为在iOS中,这种直接写@”name”是放在数据常量区,字符串放在常量区,这个字符串写多少遍都不会变
Category
改进
Category
Category
@selector(name)如果传进去的方法的名字是一样的,它返回的SEL这个对象的地址值也是一样的,SEL实际上是指向结构体的一个指针.
改进
Category
_cmd代表当前方法的@selector()
Category
其实每一个函数调用的时候,都有隐藏的参数传进来
隐式参数 隐藏传的参数一个是self,一个是_cmd
Category

setName中不能用_cmd,
Category
因为两个必须是一样的key,所以必须调用getter方法才是对的,这样取东西用的key与设置东西用的Key才能保持一致
Category
getter方法就是吧_cmd放进去,setter方法就是吧getter方法的@selector(name)放进去

关联对象的原理
Category
Category
Category

Category
manager调用associations()拿到一个HashMap,然后通过传进来的对象object生成一个key disguised_object,这个association就是HashMap,通过你传进来的key去遍历,i就是另外一个map相等于,从manager中取出hashmap,再根据对象生成的key去hashmap中找到遍历器中找到i的东西即map,这个map又能根据你传进来的key找到association,这个里面有policy和value

get方法
Category

Category
Category