手动实现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

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Flutter和Objective-C(简称OC)都是开发移动应用程序的技术,但它们在很多方面有着不同的特点。 首先,Flutter是一种跨平台的移动应用开发框架,由谷歌开发。它使用Dart语言编写,具有热重载、响应式UI框架和丰富的UI组件等特点。Flutter的一大优势是可以同时在iOS和Android平台上开发应用程序,并且拥有高性能和良好的用户体验。Flutter也支持使用原生代码进行集成,因此可以很好地与Objective-C进行交互。 Objective-C是一种面向对象的编程语言,主要用于iOS和macOS平台的应用程序开发。Objective-C采用了一种称为KVO(Key-Value Observing)的机制,允许对象对属性和值的变化进行观察和响应。通过注册观察者,当被观察对象的属性发生变化时,观察者可以接收到通知并执行相应的操作。KVO是一种非常强大的工具,可以用于实现对象之间的数据绑定和通信。 在使用Flutter开发应用时,可以与Objective-C进行集成,并利用Objective-C提供的KVO机制来实现对Flutter应用内部变量的监视和响应。这可以通过在Flutter与Objective-C之间建立桥接来实现,从而达到在Flutter应用中使用KVO的目的。 总的来说,Flutter和Objective-C KVO是两种不同的技术,Flutter是一个跨平台的移动应用开发框架,而Objective-C KVO是一种可以用于观察和响应对象属性变化的机制。在合适的场景下,可以通过Flutter与Objective-C进行集成,从而利用KVO机制来实现对Flutter应用内部变量的监视和响应。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值