iOS的KVO、KVC

turboksiOS64

一:KVO

  在实际的开发过程中,我们可能会遇到这种需求,就是需要根据一个对象某个属性值的改变,来作出不同的处理。但是实现起来比较麻烦,需要在很多地方进行判断处理,为了方便我们的开发,苹果推出了一个专门处理这种问题的解决方案,叫做KVO,负责监听属性值的改变、当发生改变的时候,可以及时的通知我们。

KVO的全程是Key-Value Observing,俗称“键值监听”,可以用于监听某个对象属性值的改变。

先来一个例子,下边在开始讲解原理。

KSPerson.h 文件

@interface KSPerson : NSObject

@property (nonatomic, strong) NSString * name;

@end

ViewController中:

#import "ViewController.h"

#import "KSPerson.h"

@interface ViewController ()

@property (nonatomic, strong) KSPerson * ks;

@end

@implementation ViewController

- (void)viewDidLoad {

    [super viewDidLoad];


    _ks= [[KSPersonalloc]init];

    _ks.name=@"Rose";

    [_ks addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];

}

- (void)touchesBegan:(NSSet *)toucheswithEvent:(UIEvent*)event{

    _ks.name=@"Jack";

}

- (void)observeValueForKeyPath:(NSString*)keyPathofObject:(id)objectchange:(NSDictionary *)changecontext:(void*)context{

    NSLog(@"%@",change);

}

@end

当我们点击屏幕的时候,会触发observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context 方法。

原理:

我们使用xocde添加断点,打印类名:



kvo

根据打印的数据可以看出,添加KVO监听的对象的class类型变成了NSKVONotifying_KSPerson,不是我们想象中的KSPerson了。

这是因为利用RuntimeAPI动态生成一个子类,并且让instance对象的isa指向这个全新的子类

当修改instance对象的属性时,会调用Foundation的_NSSetXXXValueAndNotify函数

willChangeValueForKey:

父类原来的setter

didChangeValueForKey:

内部会触发监听器(Oberser)的监听方法( observeValueForKeyPath:ofObject:change:context:)

当调用set方法的时候,NSKVONotifying_KSPerson会先调用自己的Foundation  _NSSetXXXValueAndNotifiy方法,查看_NSSet* AndNotify的存在:



借图

_NSSet*ValueAndNotify的内部实现:

    [self willChangeValueForKey:@"name"];

    //原来的setter实现

    [self didChangeValueForKey:@"name"];

调用willChangeValueForKey:

调用原来的setter实现

调用didChangeValueForKey:

didChangeValueForKey:内部会调用observer的observeValueForKeyPath:ofObject:change:context:方法


二:KVC

KVC的全称是Key-Value Coding,俗称“键值编码”,可以通过一个key来访问某个属性。

常见的API如下:

- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;

- (void)setValue:(id)value forKey:(NSString *)key;

- (id)valueForKeyPath:(NSString *)keyPath;

- (id)valueForKey:(NSString*)key; 




setvalue:forkey:



valueforkey:



相关文章

iOS音视频之视频播放

iOS音视频之视频播放

由于MPMoviePlayerController与MPMoviePlayerViewController在iOS9.0之后被弃用,所以采用AVPlayer以及AVPlayerViewControll...

百度地图自定义marker

百度地图自定义marker

#import "HomeViewController.h"#import "PaopaoView.h"@interface HomeViewControlle...

iOS图片圆角设置

iOS图片圆角设置

    UIImageView * vv = [[UIImageView alloc] initWithFrame:CGRectMake(50, 500, 250, 25...

iOS基于SceneKit的3D汽车改色

iOS基于SceneKit的3D汽车改色

基于SceneKit的汽车改色,需要修改模型文件可以去 https://www.turbosquid.com/ 自行下载,免费资源还挺多的。先上个效果图吧:核心代码: &...

RunLoop

RunLoop

RunLoop一、基础理论顾名思义1.    运行循环2.    在程序运行过程中循环做一些事情3.    是用户态和内核态之间的交互模式应...

GCD定时器

GCD定时器

NSTimer依赖于RunLoop,如果RunLoop的任务过于繁重,可能会导致NSTimer不准时。而GCD的定时器会更加准时。- (void)viewDidLoad {   ...