聊一聊KVO
2020-12-23 本文已影响0人
晨阳Xia
kvo具体的实现过程
1.首先只能作用于属性
2.要注册观察者
注册观察者之后,instance对象有什么变化?
@interface Student : NSObject{
double _no;
double _no1;
double _no2;
}
@property(nonatomic, strong) NSString *name;
@end
@implementation Student
@end
// NSKVONotifying_Student
self.studentObj1 = [[Student alloc] init];
NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
[self.studentObj1 addObserver:self forKeyPath:@"name" options:options context:nil];
// Student
self.studentObj2 = [[Student alloc] init];
同一类型的两个instance对象没有注册观察则,isa指向Student类对象
同一类型的两个instance对象,注册了观察者之后,isa指向NSKVONotifying_Student类对象。底层是runtime动态创建了NSKVONotifying_Student类型的新类,这个类是Student的子类。
// 系统重写监听类的伪代码
@interface NSKVONotifying_Student : Student
@end
@implementation NSKVONotifying_Student
// 重写了setName:方法
- (void)setName:(NSString *)name {
_NSSetIntValueAndNofify();
}
void _NSSetIntValueAndNofify() {
[self willChangeValueForKey:@"name"];
[super setName:@"name"];
[self didChangeValueForKey:@"name"];
}
- (void)didChangeValueForKey:(NSString *)key {
[observe observeValueForKeyPath:key ofObject:self change:change context:change];
}
@end
NSKVONotifying_Student
它的instance对象的isa指向它自己的class对象,他的class对象的isa指向meta-class对象。
代理和kvo的效率哪个更高
代理的效率高,kvo需要runtime动态生成类
kvo应用场景
MJRefresh
如何查看runtime重新生成的kvo新类是重写了哪些方法?
- (void)viewDidLoad {
[super viewDidLoad];
self.studentObj1 = [[Student alloc] init];
self.studentObj2 = [[Student alloc] init];
NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
[self.studentObj1 addObserver:self forKeyPath:@"name" options:options context:nil];
[self printMethodNameWithClass:object_getClass(self.studentObj1)];
[self printMethodNameWithClass:object_getClass(self.studentObj2)];
}
// 打印类中的方法
- (void)printMethodNameWithClass:(Class)class {
NSMutableString *methodNames = [NSMutableString string];
unsigned int count;
Method *methodList = class_copyMethodList(class, &count);
for (int i = 0; i < count; i++) {
Method method = methodList[i];
NSString *methodName = NSStringFromSelector(method_getName(method));
[methodNames appendFormat:@"%@ ",methodName];
}
free(methodList);
NSLog(@"className%s - allMethodName%@",class_getName(class),methodNames);
}
// 打印结果
2020-12-23 12:09:31.447274+0800 FiftyTwo[12958:724869] classNameNSKVONotifying_Student - allMethodNamesetName: class dealloc _isKVOA
2020-12-23 12:09:31.447466+0800 FiftyTwo[12958:724869] classNameStudent - allMethodName.cxx_destruct name setName:
响应式编程和kvo的区别
kvo的本质描述
利用runtime,动态生成一个子类NSKVONotifying_Class,并让instance实例指向这个子类,当修改instance对象的属性时,会调用Foundation的NSSetIntValueAndNotify函数,
NSSetIntValueAndNotify函数代码如下
- (void)setName:(NSString *)name {
_NSSetIntValueAndNofify();
}
void _NSSetIntValueAndNofify() {
[self willChangeValueForKey:@"name"];
[super setName:@"name"];
[self didChangeValueForKey:@"name"];
}
- (void)didChangeValueForKey:(NSString *)key {
[observe observeValueForKeyPath:key ofObject:self change:change context:change];
}
如何手动出发kvo
如此便可触发kvo
[self.studentObj1 willChangeValueForKey:@"name"];
[self.studentObj1 didChangeValueForKey:@"name"];