KVO 原理
里氏替换
- 利用runtime 动态生成一个子类A,且修改 instacne a对象的isa指向该全新子类
- NSKVONotifying_A 的属性被修改时,子类的set方法内部调用
willChangeValueForKey -> 原本的set实现 -> didChangeValueForKey - didChangeValueForKey会调用监听器的observeValueForKeyPath:ofObject:change:context:监听方法
动态生成的 NSKVONotifying_A 结构体:有isa、superClass、setAge方法、class方法
setAge 方法:对观察的变量重写的set方法
class 方法:重写,以隐藏自己的存在(返回再上一层),使 A 的实例调用 class 时仍返回 A 而非真实的 class NSKVONotifying_A
_isKVOA = YES;
dealloc 收尾方法重写
- 手动触发KVO
调用willChangeValueForKey 和 didChangeValueForKey,缺一不可。
[p1 willChangeValueForKey:@“age”];
// do something
[p1 didChangeValueForKey:@“age”];
- 取消kvo
automaticallyNotifiesObserversForKey 返回NO
KVC 原理
- 先调用 setKey _setKey ,找了 直接调用
- 未找到 则 查看 accessInstanceVariablesDirectly 此方法是否可以直接访问成员变量 (默认=YES)
- 可访问 按照 _key _isKey key isKey顺序取赋值,未找到报错 NSUnknownKeyException
- valueForKey类似
分类原理
- 分类文件在编译后的底层结构是 struct category_t,里面有分类的对象方法,类方法,属性,协议信息
- 在程序运行阶段,runtime将category的数据,合并到类信息中(类对象,元类对象)
- 与类扩展不同在于 一个编译时合并ro,一个运行时合并rw
- 后编译的分类方法,在消息查找时会覆盖前面的同名方法(原方法也还在)
分类添加弱引用对象 weak:加个obj,obj弱引用该对象
load 和 initialize
load
- +load 在 runtime 加载类,分类时调用
- 每个类,分类的 +load 运行时只调用一次,直接根据load方法地址调用,不走objc_msgSend
- 先调用类的 +load,先父类 再 子类
- 再调用分类的load,先编译 先调用
initialize
- +initialize 在类第一次收到消息调用
- 先调用父类的 +initialize ,再调用子类 initialize
- +initialize通过 objc_msgSend调用,如果子类未实现 +initialize,会导致父类 initialize 多次调用
关联对象
- 所有的关联对象由全局对象 AssociationsManager管理,内部有个hashMap map
- map使用 对象地址做为key ,ObejctAssociationMap 作为value
- ObejctAssociationMap 内部也是属性作为 key,ObejctAssociation作为value
- ObejctAssociation内部保存 策略 和 value
NSObject占用多少内存
16字节,因为对象最少16字节,一个指针是8字节(64位)
内存对齐小结
- 前面的地址必须是后面的地址正数倍,不是就补齐
- 整个Struct的地址必须是最大字节的整数倍
在继承条件下为
Person:isa 8字节 + age 4字节 + 内存对齐 = 16字节
Student:isa 8字节 + age 4字节 + no 4字节 (已对齐)= 16字节
网友评论