手动实现KVO

编程入门 行业动态 更新时间:2024-10-08 00:24:30

手动实现<a href=https://www.elefans.com/category/jswz/34/1632670.html style=KVO"/>

手动实现KVO

  KVO内部实现原理

  • KVO是基于runtime机制实现的
  • 当某个类的属性对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的setter 方法。派生类在被重写的setter方法内实现真正的通知机制
  • 如果原类为BreadModel,那么生成的派生类名为NSKVONotifying_BreadModel
  • 每个类对象中都有一个isa指针指向当前类,当一个类对象的第一次被观察,那么系统会偷偷将isa指针指向动态生成的派生类,从而在给被监控属性赋值时执行的是派生类的setter方法
  • 键值观察通知依赖于NSObject 的两个方法: willChangeValueForKey:和 didChangevlueForKey:;在一个被观察属性发生改变之前, willChangeValueForKey:一定会被调用,这就 会记录旧的值。而当改变发生后,didChangeValueForKey:会被调用,继而 observeValueForKey:ofObject:change:context:也会被调用。
  • 补充:KVO的这套实现机制中苹果还偷偷重写了class方法,让我们误认为还是使用的当前类,从而达到隐藏生成的派生类

  • 实例如下:

#import "ViewController.h"
#import "BreadModel.h"
#import "NSObject+KVO.h"@interface ViewController ()@property (nonatomic, strong) BreadModel *brdModel;@property (nonatomic, copy) NSString *time;@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];self.view.backgroundColor = [UIColor whiteColor];self.time = @"2019.8.8";
}-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{self.brdModel.offer_sum = self.time;self.time = @"2020.10.10";
}-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{[self.brdModel cum_removeObserver:self forKeyPath:@"offer_sum" context:@"789"];
}/*
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context{NSLog(@"%@---%@--%@--%@",keyPath,object,change,context);
}*/- (void)cum_observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context{NSLog(@"%@",keyPath);
}-(BreadModel *)brdModel{if (!_brdModel) {_brdModel = [[BreadModel alloc] init];/*[_brdModel addObserver:self forKeyPath:@"offer_sum" options:NSKeyValueObservingOptionNew context:@"789"];*/[_brdModel cum_addObserver:self forKeyPath:@"offer_sum" options:NSKeyValueObservingOptionNew context:@"789"];}return _brdModel;
}@end#import "NSKVONotifying_BreadModel.h"
#import <objc/runtime.h>
#import "NSObject+KVO.h"@implementation NSKVONotifying_BreadModel-(void)setOffer_sum:(NSString *)offer_sum{/*  改变真正需要改变的类的值*/[super setOffer_sum:offer_sum];/*  监听的值改变时,回调通知监听者*/id observer = objc_getAssociatedObject(self, @"observer");id keyPath = objc_getAssociatedObject(self, @"keyPath");id context = objc_getAssociatedObject(self, @"context");if (observer) [observer cum_observeValueForKeyPath:keyPath ofObject:self change:nil context:nil];
}#import "NSObject+KVO.h"
#import <objc/runtime.h>
#import "NSKVONotifying_BreadModel.h"@implementation NSObject (KVO)- (void)cum_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context{/*  使当前对象的isa指向新的派生类(Person_KVO),就会调用派生类的set方法*/object_setClass(self, [NSKVONotifying_BreadModel class]);/*  给分类添加属性*/objc_setAssociatedObject(self, @"observer", observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);objc_setAssociatedObject(self, @"keyPath", keyPath, OBJC_ASSOCIATION_RETAIN_NONATOMIC);objc_setAssociatedObject(self, @"context", [NSString stringWithFormat:@"%@",context], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}- (void)cum_removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(nullable void *)context {/*  子类去实现,处理业务逻辑*/objc_setAssociatedObject(self, @"observer", nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);objc_setAssociatedObject(self, @"keyPath", nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);objc_setAssociatedObject(self, @"context", nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}- (void)cum_observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context{/*  子类去实现,处理业务逻辑*/NSLog(@"子类去实现,处理业务逻辑");
}
@end

 

更多推荐

手动实现KVO

本文发布于:2024-02-14 11:22:01,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1763073.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:KVO

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!