KVC/KVO 使用细节和调用顺序

Key-Value Coding (KVC)
Key-Value Coding (KVC)
KVC,即是指 NSKeyValueCoding,一个非正式的 Protocol,提供一种机制来间接访问对象的属性。KVO 就是基于 KVC 实现的关键技术之一。
 
一个对象拥有某些属性。比如说,一个 Person 对象有一个 name 和一个 address 属性。以 KVC 说法,Person 对象分别有一个 value 对应他的 name 和 address 的 key。 key 只是一个字符串,它对应的值可以是任意类型的对象。从最基础的层次上看,KVC 有两个方法:一个是设置 key 的值,另一个是获取 key 的值。
 
 
// 重写setter方法和getter 方法:
1. Dog对象有属性:
@property(nonatomic,copy)NSString *name;
2. 如果同时重写setter和getter方法:
// 记住: 如果同时重写setter和getter方法,系统不会自动生成_name的成员变量.
需要  @synthesize name = _name;
以告诉系统,你要帮我生成_name 
 
3.  [myDog setValue:@"MBXxx" forKey:@"_name"];
@“_name” @“name 都可以访问到该成员变量
 
4.  NSString *age = [myDog valueForKey:@"age"];
   调用这句代码时,
1) 系统先去找该变量有没有getter方法. 如果有,调用getter方法取值
2) 如果没有getter方法,系统会查找有没有age成员或者_age成员.
 
5. 如果仅仅在.m文件中声明了全局的变量:
{
    @public
    NSString *age;
}
这时,只能通过KVC模式来赋值和取值.
// 注: 先赋值,再取.
[myDog setValue:@"10" forKey:@"age"];
        NSString *age = [myDog valueForKey:@"age"];
        NSLog(@"age ==== %@",age);
打印结果: age === 10
说明,赋值和取值过程成功.

KVO:
即:Key-Value Observing,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知。简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了。
// dog.m 代码:
#import "Dog.h"
@implementation Dog
{
    @public
    NSString *age;
}
@synthesize name = _name;
-(void)setName:(NSString *)name{ // 1
    NSLog(@"xxxxx");
    _name = name;
}
-(NSString *)name{ // 2
    NSLog(@"AAAAA");
    return _name;
}
@end

person.m 代码:
#import "Person.h"
@implementation Person

-(void)setDog:(Dog *)dog{ // 3
    _dog = dog;
    // 添加当前对象为观察者
    [_dog addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew NSKeyValueObservingOptionOld context:@"hello kvo"];
}
-(void)dealloc{ // 6
    [_dog removeObserver:self forKeyPath:@"name"];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ // 4
    NSLog(@"context==%@",context);
    if([object isKindOfClass:[Dog class]] && [keyPath isEqualToString:@"name"]){
        NSString *new = change[NSKeyValueChangeNewKey];
        NSLog(@"new === %@",new);
    }
}
@end
下面看看调用过程是怎样的?
        Person *p = [[Person alloc]init];
        p.dog = myDog;
        myDog.name @"fyz//5
1)调用 p.dog = myDog; 方法时,走 方法3.
2)然后来到 方法5
3)来到 方法2(getter) //打印了AAAA
4)然后 来到 方法1(setter) // 打印XXXX (这里为什么?需要测试)
5 ) 又来到 方法2( getter ) //打印了AAAA (这里又为什么?需要测试)
6 ) 然后来到 方法4 // 打印new ===
7 ) 最后走析构函数 方法6
// 没有加入观察者模式时,只会调一次 方法1(set方法),相当于观察者模式的存在.
先调用了一次getter方法, 再调一次setter方法,再调一次getter方法.
posted @ 2015-04-24 12:21  toxicanty  阅读(426)  评论(0编辑  收藏  举报