iOS学习之KVO、KVC

本文深入探讨了Objective-C与Swift两种编程语言在iOS开发领域的应用,包括它们各自的优势、特点以及如何在实际项目中进行选择与使用。

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

一、kvo:key-value-observing 提供了一种机制,当制定的对象的属性被修改后就会接受到通知。就是每次指定的被观察者的对象的属性被修改后,kvo就会通知相应的观察者。


举例:

Person *p = [[Person alloc] init];
p.age = 20;
//设置观察者 观察p的age属性的变化
[p addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];

//改变age属性

p.age = 30;

调用以下方法


/**
 *  当监控的某个属性的值改变了就会调用
 *  @param keyPath 属性名(哪个属性改了?)
 *  @param object  哪个对象的属性被改了?
 *  @param change  属性的修改情况(属性原来的值、属性最新的值)
 *  @param context void * == id
 */
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
   
NSLog(@"%@对象的%@属性改变了:%@", object, keyPath, change);
}

移除观察者
- (void)dealloc
{
    [
self.p removeObserver:self forKeyPath:@"age"];
}

kvo内部实现原理:
监听p的age属性前,p的isa指针指向HMPerson类,这时调用HMPerson中age的set方法, 当开始监听p的age属性系统会自动创建NSKVONotifying_HMPerson,它继承HMPerson 并重写age 的set方法  在该方法中调用
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 方法

kvc:key-value-coding 的简称,它是一种可以直接通过字符串的名字(key)来访问类属性的机制,而不是通过调用set、get方法访问
// key value coding : 间接通过字符串类型的 key 取出对应的属性值
// KVC 的价值
// 1.可以访问私有成员变量的值
// 2.可以间接修改私有成员变量的值(替换系统自带的导航栏、tabbar

以下为几种用法举例:
1、获取类的属性值
     [[p valueForKey:@"age"] intValue]
2、获取类的私有属性(先调用height的get方法,然后调用_height)
    [[p valueForKey:@"height"] floatValue]
3、 valueForKey 与  valueForKeyPath 区别
keyPath 包含了 key 的功能
key:只能访问当前对象的属性
keyPath:能利用.运算符一层一层往内部访问属性
[p valueForKeyPath:@"dog.name"])

4、通过kvc获取一个对象中另一个对象的属性的内容
[p valueForKeyPath:@"books.@count"] 计算数组的长度

5、获取对象的数组中的对象的内容
 NSArray *names = [p valueForKeyPath:@"books.name"];
//    NSArray *names = [p.books valueForKeyPath:@"name"];

6、数组书中所有书的价格的总和,还可以求平局值、最大值、最小值等
@avg:平均值
@count:总数
@max:最大
@min:最小
@sum:总数

double sumPrice = [[p valueForKeyPath:@"books.@sum.price"] doubleValue];


KVC的实现细节

a. setValue:forKey的搜索方式:

1. 首先搜索set<Key>:方法

如果成员用@property,@synthsize处理,因为@synthsize告诉编译器自动生成set<Key>:格式的setter方法,所以这种情况下会直接搜索到。

注意:这里的<Key>是指成员名,而且首字母大写。下同。

2. 上面的setter方法没有找到,如果类方法accessInstanceVariablesDirectly返回YES(注:这是NSKeyValueCodingCatogery中实现的类方法,默认实现为返回YES)。

那么按_<key>,_is<Key>,<key>,is<key>的顺序搜索成员名。


3. 如果找到设置成员的值,如果没有调用setValue:forUndefinedKey:。

b. valueForKey:的搜索方式:

1. 首先按get<Key>、<key>、is<Key>的顺序查找getter方法,找到直接调用。如果是bool、int等内建值类型,会做NSNumber的转换。

2. 上面的getter没有找到,查找countOf<Key>、objectIn<Key>AtIndex:、<Key>AtIndexes格式的方法。

如果countOf<Key>和另外两个方法中的一个找到,那么就会返回一个可以响应NSArray所有方法的代理集合 (collection proxy object)。发送给这个代理集合(collection proxy object)的NSArray消息方法,就会以countOf<Key>、 objectIn<Key>AtIndex:、<Key>AtIndexes这几个方法组合的形式调用。还有一个可选的 get<Key>:range:方法。

3. 还没查到,那么查找countOf<Key>、enumeratorOf<Key>、memberOf<Key>:格式的方法。

如果这三个方法都找到,那么就返回一个可以响应NSSet所有方法的代理集合(collection proxy object)。发送给这个代理集合(collection proxy object)的NSSet消息方法,就会以countOf<Key>、enumeratorOf<Key>、 memberOf<Key>:组合的形式调用。

4. 还是没查到,那么如果类方法accessInstanceVariablesDirectly返回YES,那么按_<key>,_is<Key>,<key>,is<key>的顺序直接搜索成员名。

5. 再没查到,调用valueForUndefinedKey:。







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值