iOS Principle:KVO(下)

简介: iOS Principle:KVO(下)

NSKVONotifyin_Person内部结构是怎样的?


首先我们知道,NSKVONotifyin_Person作为Person的子类,其superclass指针指向Person类,并且NSKVONotifyin_Person内部一定对setAge方法做了单独的实现,那么NSKVONotifyin_Person同Person类的差别可能就在于其内存储的对象方法及实现不同。 我们通过runtime分别打印Person类对象和NSKVONotifyin_Person类对象内存储的对象方法


{
    p1.age = 10;
    [self printMethods: object_getClass(p2)];
    [self printMethods: object_getClass(p1)];
    [p1 removeObserver:self forKeyPath:@"age"];
}
// runtime to print class methods
- (void)printMethods:(Class)cls {
    unsigned int count ;
    Method *methods = class_copyMethodList(cls, &count);
    NSMutableString *methodNames = [NSMutableString string];
    [methodNames appendFormat:@"%@ method list: ", cls];
    for (int i = 0 ; i < count; i++) {
    Method method = methods[i];
    NSString *methodName  = NSStringFromSelector(method_getName(method));
    [methodNames appendString:@"\n"];
    [methodNames appendString: methodName];
    }
    NSLog(@"%@",methodNames);
    free(methods);
}


上述打印内容如下


通过上述代码我们发现NSKVONotifyin_Person中有4个对象方法。分别为setAge: class dealloc _isKVOA,那么至此我们可以画出NSKVONotifyin_Person的内存结构以及方法调用顺序。


image.png


这里NSKVONotifyin_Person重写class方法是为了隐藏NSKVONotifyin_Person。不被外界所看到。我们在p1添加过KVO监听之后,分别打印p1和p2对象的class可以发现他们都返回Person。


NSLog(@"%@,%@",[p1 class],[p2 class]);


如果NSKVONotifyin_Person不重写class方法,那么当对象要调用class对象方法的时候就会一直向上找来到nsobject,而nsobect的class的实现大致为返回自己isa指向的类,返回p1的isa指向的类那么打印出来的类就是NSKVONotifyin_Person,但是apple不希望将NSKVONotifyin_Person类暴露出来,并且不希望我们知道NSKVONotifyin_Person内部实现,所以在内部重写了class类,直接返回Person类,所以外界在调用p1的class对象方法时,是Person类。这样p1给外界的感觉p1还是Person类,并不知道NSKVONotifyin_Person子类的存在。 那么我们可以猜测NSKVONotifyin_Person内重写的class内部实现大致为


- (Class) class {
// 得到类对象,在找到类对象父类
    return class_getSuperclass(object_getClass(self));
}


验证


验证 didChangeValueForKey:内部会调用observer的observeValueForKeyPath:ofObject:change:context:方法 我们在Person类中重写willChangeValueForKey:和didChangeValueForKey:方法,模拟他们的实现。

- (void)setAge:(int)age {
    NSLog(@"setAge:");
    _age = age;
}
- (void)willChangeValueForKey:(NSString *)key {
    NSLog(@"willChangeValueForKey: - begin");
    [super willChangeValueForKey:key];
    NSLog(@"willChangeValueForKey: - end");
}
- (void)didChangeValueForKey:(NSString *)key {
    NSLog(@"didChangeValueForKey: - begin");
    [super didChangeValueForKey:key];
    NSLog(@"didChangeValueForKey: - end");
}


再次运行来查看didChangeValueForKey的方法内运行过程,通过打印内容可以看到,确实在didChangeValueForKey方法内部已经调用了observer的observeValueForKeyPath:ofObject:change:context:方法。


如何手动调用 KVO


被监听的属性的值被修改时,就会自动触发KVO。如果想要手动触发KVO,则需要我们自己调用willChangeValueForKey和didChangeValueForKey方法即可在不改变属性值的情况下手动触发KVO,并且这两个方法缺一不可。


{
    Person *p1 = [[Person alloc] init];
    p1.age = 1.0;
    NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
    [p1 addObserver:self forKeyPath:@"age" options:options context:nil];
    [p1 willChangeValueForKey:@"age"];
    [p1 didChangeValueForKey:@"age"];
    [p1 removeObserver:self forKeyPath:@"age"];
}


image.png


通过打印我们可以发现,didChangeValueForKey方法内部成功调用了observeValueForKeyPath:ofObject:change:context:,并且age的值并没有发生改变。


小结


当一个对象使用了KVO监听,iOS系统会修改这个对象的isa指针,改为指向一个全新的通过Runtime动态创建的子类,子类拥有自己的set方法实现,set方法实现内部会顺序调用willChangeValueForKey方法、原来的setter方法实现、didChangeValueForKey方法,而didChangeValueForKey方法内部又会调用监听器的observeValueForKeyPath:ofObject:change:context:监听方法。



以上文章整理自:https://juejin.cn/post/6844903593925935117


目录
相关文章
|
iOS开发
iOS Principle:CGAffineTransform
iOS Principle:CGAffineTransform
183 0
iOS Principle:CGAffineTransform
|
安全 Unix API
iOS Principle:CALayer(下)
iOS Principle:CALayer(下)
173 0
iOS Principle:CALayer(下)
|
iOS开发
iOS Principle:CALayer(中)
iOS Principle:CALayer(中)
151 0
iOS Principle:CALayer(中)
|
API C语言 iOS开发
iOS Principle:CALayer(上)
iOS Principle:CALayer(上)
180 0
iOS Principle:CALayer(上)
|
存储 缓存 iOS开发
iOS Principle:weak
iOS Principle:weak
169 0
iOS Principle:weak
|
存储 iOS开发
iOS Principle:Notification(下)
iOS Principle:Notification(下)
117 0
iOS Principle:Notification(下)
|
设计模式 iOS开发
iOS Principle:Notification(上)
iOS Principle:Notification(上)
133 0
iOS Principle:Notification(上)
|
Web App开发 JSON 移动开发
iOS Principle:ReactNative(下)
iOS Principle:ReactNative(下)
184 0
iOS Principle:ReactNative(下)
|
移动开发 前端开发 JavaScript
iOS Principle:ReactNative(中)
iOS Principle:ReactNative(中)
126 0
iOS Principle:ReactNative(中)
|
移动开发 开发框架 自然语言处理
iOS Principle:ReactNative(上)
iOS Principle:ReactNative(上)
138 0