KVO/KVC

什么是KVO

  • KVO是Key-Value Observing的首字母缩写
  • KVO是Object-C对观察者设计模式的实现
  • Apple使用了isa混写(isa-swizzling)来实现KVO

KVO 提供一种机制,指定一个被观察对象(例如 A 类),当对象某个属性(例如 A 中的字符串 name)发生更改时,对象会获得通知,并作出相应处理;【且不需要给被观察的对象添加任何额外代码,就能使用 KVO 机制】
用一张图来描述一下KVO的实现机制

KVO

上图可以看出,注册一个对象的观察者的时候,实际上是调用了系统的- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;这个方法,调用这个方法后观察者观察对象A中的某个属性,然后系统会在运行时动态的创建一个NSKVONotifying_A的这么样一个类,原来的对象A的isa指针重新指向了NSKVONotifying_A这个类,把isa的指向进行修改就是isa混写技术.NSKVONotifying_A是类A的子类,并重写了其中的Setter方法,通过对Setter方法的重写达到可以通知所有观察者的目的.
接下来,在XCode工程当中,来实际通过Setter方法的设置,KVO的监听来感受一下KVO的实现.
创建两个文件,MyObject和MyObserver.

  • MyObject
@interface MyObject : NSObject
@property (nonatomic,assign) int value;
-(void)increase;
@end
@implementation MyObject

-(instancetype)init
{
    self = [super init];
    if (self) {
        _value = 0;
    }
    return self;
}

-(void)increase
{
    _value += 1;
}

@end
  • MyObserver
@implementation MyObserver
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    NSNumber *valueNum = [change valueForKey:NSKeyValueChangeNewKey];
    NSLog(@"value is %@",valueNum);
}
@end

然后在AppDelegate中进行KVO的监听

  • AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    
    MyObject *obj = [[MyObject alloc]init];
    MyObserver *observer = [[MyObserver alloc]init];
    
    //调用KVO方法监听obj的value属性的变化
    [obj addObserver:observer forKeyPath:@"value" options:NSKeyValueObservingOptionNew context:NULL];
    obj.value = 1;
    return YES;
}

可以看到控制台打印出了结果


说明监听成功了.
在obj.value那里打个断点,看看MyObject是怎么被改写的.


不出所料,在监听的属性Value被改写后,MyObject变成了NSKVONotifying_MyObject了.
为什么调用Setter方法就可以实现这种KVO的监听呢.

重写的Setter添加的方法
  • -(void)willChangeValueForKey:(NSString *)key
  • -(void)didChangeValueForKey:(NSString *)key

那么在NSKVONotifying_MyObject中的Setter方法就变成了下面这样

-(void)setValue:(id)obj
{
    [self willChangeValueForKey:@"keyPath"];
    //调用父类,也就是原类的实现
    [super setValue:obj];
    [self didChangeValueForKey:@"keyPath"];
}

接下来有两个问题.

1.通过KVC设置Value能否生效

这个问题用代码来验证一下就可以了,如下所示

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    MyObject *obj = [[MyObject alloc]init];
    MyObserver *observer = [[MyObserver alloc]init];
    //调用KVO方法监听obj的value属性的变化
    [obj addObserver:observer forKeyPath:@"value" options:NSKeyValueObservingOptionNew context:NULL];
    obj.value = 1;
    // 使用kvc来改变value的值
    [obj setValue:@2 forKey:@"value"];
    return YES;
}

结果控制台打印如下:



说明使用KVC设置属性的方式是可以出发KVO的,说明KVC设置属性是触发了Setter方法

2.使用成员变量赋值会出发KVO吗

我们在AppDelegate调用obj的increase方法,发现控制台只打印了value is 1,说明对成员变量赋值不会触发KVO,但对increate方法进行以下操作就不一样了.
不过如果我们把increase方法变成下面这样,再运行试试

-(void)increase
{
    [self willChangeValueForKey:@"value"];
    _value += 1;
    [self didChangeValueForKey:@"value"];
}

发现又触发了KVO
所以根据上面的实验总结出下面几点

  • 使用setter方法改变值KVO才会生效
  • 使用setValue:forKey:改变KVO才会生效
  • 成员变量直接修改需手动添加KVO才会生效

KVC

KVC是Key-Value coding的缩写,也就是键值编码,和键值编码相关的两个方法就是下面这两个

  • -(id)valueForKey:(NSString *)key
    这个可以调用某个实例的ValueForKey:方法,来获取和key同名或相似名称的实例变量的值
  • -(void)setValue forKey:(NSString *)key
    根据这个方法可以设置某一个对象和这个key同名或者相似名称的实例变量的值.
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 1.KVO KVO即键值监听。KVO模式在广泛应用的MVC模式中应用很广泛。在C中注册C为M中属性的监听者,当M中...
    雪山飞狐_91ae阅读 572评论 0 1
  • 在iOS开发过程中,我们经常会听到或者用到KVO,KVC,NSNotificationCenter等,但是很多时候...
    dullgrass阅读 7,062评论 14 133
  • KVC KVC定义 KVC(Key-value coding)键值编码,就是指iOS的开发中,可以允许开发者通过K...
    暮年古稀ZC阅读 2,127评论 2 9
  • KVO: KVO的全称是Key-Value Observing,俗称“键值监听”,可以用于监听某个对象属性值的改变...
    曹来东阅读 622评论 0 0
  • Key Value Observing(KVO)键值观察,它提供一种机制,当指定的对象的属性被修改后,则对象就会接...
    小小土豆dev阅读 225评论 0 5