XB_KVO与KVC

本文详细介绍了Objective-C中的KVO(键值监听)和KVC(键值编码)机制。KVO用于监听对象属性变化,通过动态生成子类实现;KVC则提供了一种通过键名访问和修改对象属性的方法,且能触发KVO。文章深入探讨了两者的工作原理及内部实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.KVO

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

KVO本质是利用RuntimeAPI动态生成一个子类,并且让这个instance对象的isa指向这个全新的子类,当修改instance对象的属性时,会调用Foundtion的_NSSetXXXValueAndNotify函数,该函数包含三部分

willChangeValueForKey:

super 父类的setter方法

didChangeValueForKey:

 

在didChangeValueForKey函数内部会触发监听器(observer)的监听方法(observeValueForKeyPath: ofObject:change: context:)

 

以下是生成的子类中的伪代码:

#import "NSKVONotifying_MJPerson.h"

@implementation NSKVONotifying_MJPerson

- (void)setAge:(int)age
{
    _NSSetIntValueAndNotify();
}

// 伪代码
void _NSSetIntValueAndNotify()
{
    [self willChangeValueForKey:@"age"];
    [super setAge:age];
    [self didChangeValueForKey:@"age"];
}

- (void)didChangeValueForKey:(NSString *)key
{
    // 通知监听器,某某属性值发生了改变
    [oberser observeValueForKeyPath:key ofObject:self change:nil context:nil];
}

监听器可以手动触发KVO,

[xxx willChangeValueForKey:@"key"];

  [xxx didChangeValueForKey:@"key"];

的时候就会触发,当然这里值没有改变。

 

直接修改成员变量不会触发KVO

person->_age = 10;

不会触发

可以配合手动触发实现值改变,也就是_NSSet*ValueAndNotify的内部实现

 [person willChangeValueForKey:@"age"];
  perosn->_age = 10;
 [person didChangeValueForKey:@"age"];

 /*--------------------------------------------------------------------验证NSKVONotifying_XXX子类的存在-------------------------------------------*/

//注:person1进行值监听,person2不进行值监听

    [self.person1 addObserver:self forKeyPath:@"age" options:options context:@"123"];
    
    NSLog(@"person1添加KVO监听之后 - %@ %@",
          object_getClass(self.person1),
          object_getClass(self.person2));
    NSLog(@"person1添加KVO监听之后 - %p %p",
          [self.person1 methodForSelector:@selector(setAge:)],
          [self.person2 methodForSelector:@selector(setAge:)]);

会发现person1的类对象是NSKVONotifying_MJPerson,方法打印是 (Foundation`_NSSetIntValueAndNotify),而person2的类对象依然是MJPerson,方法打印是(Interview01`-[MJPerson setAge:] at MJPerson.m:13)

但是如果用[self.person1 class]调用会发现打印的类对象是Person,这里猜测是在NSKVONotifying_MJPerson中重写了class方法,屏幕内部实现,隐藏了NSKVONotifying_MJPerson类的存在

2.KVC

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

- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
- (void)setValue:(id)value forKey:(NSString *)key;
- (id)valueForKeyPath:(NSString *)keyPath;
- (id)valueForKey:(NSString *)key; 

1.KVC赋值原理 

 其中+ (BOOL)accessInstanceVariablesDirectly表示是否允许直接修改成员变量的值,默认是YES

可以看到调用set方法的时候是按照setKey_setKey的顺序调用的,给成员变量赋值的时候是按照_key、_isKey、key、isKey的顺序赋值的,就算同时存在并且顺序打乱也是按照这个顺序赋值。

2.KVC取值原理

调用顺序也是固定死的。

KVC可以触发KVO!!

[person setValue:@10 forKey:@"age"];

内部实现其实是
[person willChangeValueForKey:@"age"];
 person->_age = 10;
[person didChangeValueForKey:@"age"];

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值