KVO
- 通过打印
被监听实例对象的isa指针,可以发现,被监听实例对象的isa不再指向类对象,而是指向NSKVONotifying_MJPerson NSKVONotifying_MJPerson是使用Runtime动态创建的一个类,是MJPerson的子类
NSKVONotifying_MJPerson 伪代码
- 通过
[self.person1 methodForSelector:@selector(setAge:)]获取方法实现的地址 - 通过LLDB 的命令
p (IMP)0x1069189e4获取方法的名称
#import "MJPerson.h"
@interface NSKVONotifying_MJPerson : MJPerson
@end
#import "NSKVONotifying_MJPerson.h"
@implementation NSKVONotifying_MJPerson
- (void)setAge:(int)age
{
_NSSetIntValueAndNotify();
}
// 伪代码
void _NSSetIntValueAndNotify()
{
[self willChangeValueForKey:@"age"];
[super setAge:age];
[self didChangeValueForKey:@"age"];
}
- (void)didChangeValueForKey:(NSString *)key
{
// 通知监听器,某某属性值发生了改变
[oberser observeValueForKeyPath:key ofObject:self change:nil context:nil];
}
@end
NSKVONotifying_MJPerson 类对象指向自己的元类对象
未使用KVO监听的对象
使用KVO监听的对象
总结:使用了
KVO,会产生一个MJPerson的子类(NSKVONotifying_MJPerson),会改变MJPerson的isa指向新产生的子类,同时在新的子类里面会重写setAge:方法,以及新增三个方法
获取方法数组
- (void)printMethodNamesOfClass:(Class)cls
{
unsigned int count;
// 获得方法数组
Method *methodList = class_copyMethodList(cls, &count);
// 存储方法名
NSMutableString *methodNames = [NSMutableString string];
// 遍历所有的方法
for (int i = 0; i < count; i++) {
// 获得方法
Method method = methodList[i];
// 获得方法名
NSString *methodName = NSStringFromSelector(method_getName(method));
// 拼接方法名
[methodNames appendString:methodName];
[methodNames appendString:@", "];
}
// 释放
free(methodList);
// 打印方法名
NSLog(@"%@ %@", cls, methodNames);
}
可以看到 NSKVONotifying_MJPerson 内部的方法名
| NSKVONotifying_MJPerson | 类型 | 实现 |
|---|---|---|
setAge: | 重写 | 实现Foundation的_NSSetIntValueAndNotify方法 |
class | 新增 | 屏蔽内部实现,隐藏了NSKVONotifying_MJPerson类对象 |
dealloc | 新增 | 清理现场 |
_isKVOA | 新增 |
_NSSetIntValueAndNotify内部实现
1. [self willChangeValueForKey:@"age"]
2. 原来的setter实现
3. [self didChangeValueForKey:@"age"]
didChangeValueForKey:内部会调用observer的observeValueForKeyPath:ofObject:change:context:方法
KVO的手动实现,手动调用 willChangeValueForKey 和 didChangeValueForKey 两个方法
_NSSet*ValueAndNotify 包括很多的基本数据类型
KVC
使用KVC设置属性时候,会触发KVO,即使没有set方法,也会触发KVO,因为KVC底层调用了- (void)willChangeValueForKey:(NSString *)key 和 - (void)didChangeValueForKey:(NSString *)key 两个方法
举例: 查找顺序(属性名为
age) _age _isAge age isAge
NSNotification
- 是使用
观察者模式来实现的用于跨层传递消息的机制 - 传递方式是一对多
通知和代理的区别:
- 代理是
代理模式实现的,通知是观察者模式实现的 - 代理是一对一的,通知是一对多的