一、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:能利用.运算符一层一层往内部访问属性
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:。