-
准备工作
-
添加类扩展,并添加属性、方法
-
在分类中添加属性,并实现set、get方法
-
-
类扩展
-
类别和类扩展的区别
- 类别
- 专门给类添加新的方法
- 不能给类添加成员属性,添加了成员属性也是无法取到的
- 可以通过
runtime给分类添加属性(通过关联对象) - 分类中
@property定义变量只会生成getter、setter方法的声明,不能生成方法的实现和带下划线的成员变量
- 类扩展
- 可以说是特殊的分类,也叫做匿名分类
- 可以给类添加成员属性和方法,但是成员属性和方法都是私有的
- 类别
-
类扩展底层探索
添加类扩展后clong对应文件编译查看编译后的文件clang -rewrite-objc main.m -o main.cpp发现编译时期就已经类扩展中的成员属性和方法添加到类中了,也可以运行源码验证
总结
- 类的扩展在编译时期会作为类的一部分,和类一起编译进来
- 类的扩展只是声明,依赖于当前的主类,没有.m文件,可以理解为一个·h文件
-
-
关联对象
-
分类中特性2、4验证
注释掉分类中属性点额setter和getter方法给分类中的属性赋值然后运行发现赋值编译是可以通过的,但是运行之后崩溃提示找不到
setter方法,初步验证了分类中属性的getter、setter方法的声明是有的但是没有实现, -
分类特性3验证
实现setter和getter方法分别通过objc_setAssociatedObject设置和objc_getAssociatedObject方法取值如下:在运行发现
此时既能赋值也能取到值
-
objc_setAssociatedObject和objc_getAssociatedObject方法源码分析-
objc_setAssociatedObject- 搜索源码查看入参含义
- policy属性策略
objc_AssociationPolicy _object_set_associative_reference
通过源码发现objc_setAssociatedObject底层调用的是_object_set_associative_reference方法实现功能再看
_object_set_associative_reference的源码实现通过源码可以总结为以下步骤
- 创建
AssociationsManager变量 - 获取静态哈希map,
AssociationsHashMap - 判断value是否存在,存在的话通过try_emplace方法,并创建一个空的
ObjectAssociationMap去取查询的键值对:不存在就走 : 关联对象-插入空流程 - 如果发现没有这个key就插入一个空的BucketT进去并返回true这一步主要是在
try_emplace方法中实现LookupBucketFor源码实现如何辨别
try_emplace方法中调用的是哪个方法,通过入参属性修饰符来判断 内部调用的LookupBucketFor方法源码实现 - 通过
setHasAssociatedObjects方法标记对象存在关联对象即置isa指针的has_assoc属性为true - 用当前policy和value组成了一个
ObjcAssociation替换原来BucketT中的空 - 标记一下
ObjectAssociationMap的第一次为 false
- 创建
- 关联对象涉及的map结构
- 搜索源码查看入参含义
-
objc_getAssociatedObject- 搜索源码查看入参含义
_object_get_associative_reference
通过源码发现底层调用的是_object_get_associative_reference方法来实现功能再看
_object_get_associative_reference源码实现
- 搜索源码查看入参含义
-
-
关联对象流程图
-