聊一聊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"];

上一篇 下一篇

猜你喜欢

热点阅读