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
- 是使用
观察者模式
来实现的用于跨层传递消息的机制 - 传递方式是一对多
通知和代理的区别:
- 代理是
代理模式
实现的,通知是观察者模式
实现的 - 代理是一对一的,通知是一对多的