KVC和KVO

kvc(key value coding),它是一种可以直接通过字符串的名字(key)来访问类属性的机制,可以直接通过set value forKey 和valueforkey方法来给实例变量赋值和取值,kvc的机制就是首先判断属性是否有get和set方法,如果不存在将在内部查找_key 和 key的实例变量,如果没有将会调用setvalueforundefinedkey,如果没有这个方法,运行报错



优点:可以减少代码量,没有properey声明的变量也可以通过kvc来设置
缺点:如果key值写错,编写时不会报错,运行时会报错

kvo:一个对象可以观察另一个对象的值,并且能够发现值的变化,或者说一个对像与另一个对象保持同步的一种方法,当被观察的对象状态发生改变时,观察者马上做出相应,但是有一个缺点,它只能对对象的属性做出反应,而不会对象的方法做出反应

比如 svpulltorefresh,上啦加载,下拉刷新就用到了这个类

kvo的优点:可以同步对象,能够观察对象的最新值和先前值,而且不需要额外的代码来允许观察者能够被观察
缺点:当我们注册监听的时候,监听对象的属性和写错了,程序编译时不会报错,因为是字符串编译器也不会检查

KVC是KeyValue Coding的简称,它是一种可以直接通过字符串的名字(key)来访问类属性的机制。而不是通过调用Setter、Getter方法访问

具体的例子:

1.创建一个people类,继承与NSObject

   @interface People : NSObject
   @property(nonatomic,copy)NSString *name;//people的属性
   @end

 当我们在类外访问的时候,可以通过打点调用属性

    People *p=[People new];//创建一个people
    p.name=@"李四";

也可以通过kvc的方式来调用

    People *people=[People new];
    [people setValue:@"张三" forKey:@"name"];
    NSLog(@"%@",people.name);//张三
    NSString *name=[people valueForKey:@"name"];
    NSLog(@"%@",name);
你或许说了,打点调用不是可以更加方便吗?可以kvo有一个打点调用不能实现的方法:例如

@interface People : NSObject
   {

           NSString *_name;

   }
   @end

_name是people类的全局变量,这样我们就不能进行打点调用了,这时候kvc就派上用场了

  People *people=[People new];
    [people setValue:@"张三" forKey:@"name"];
    NSLog(@"%@",people.name);//张三
    NSString *name=[people valueForKey:@"name"];//得到值
    NSLog(@"%@",name);//张三

你会发现程序居然没有报错,而且执行成功了

@interface People : NSObject
   {

           NSString *name;

   }
   @end

和_name同理

但是我们调用一个不存在的key时,程序就会崩溃

比如我们在程序外调用 [people setValue:@"张三" forKey:@"name1"];

Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<People 0x106f14270> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key name1.' 原因就是因为没有name1这个key值

结果和上面一样:不管结果如果,你都会发先系统调用了属性的get方法,所以总结如下首先会调用set(get)方法如果set(get)方法不存在,会找到_key当_key不存在时,会找到key当key不存在时,会crash。

2.kvc可以根据路径值访问属性和对属性赋值,例如

我们有一个car类,有一个people类

@interface People : NSObject

@property (nonatomic,strong) NSString *name;
@property (nonatomic,strong) NSNumber *age;

@property (nonatomic,strong) Car *car;
@end

@interface Car : NSObject
@property (nonatomic,strong) NSString *name;
@property (nonatomic,strong) UIColor *bgColor;
@end

类外调用:

 People *people = [People new];

 [people setValue:@"SUV" forKeyPath:@"car.name"];

NSString *carName=[people valueForKey:@"car.name"];//suv

3.可以通过字典对属性赋值:

例如:

@interface People : NSObject

@property (nonatomic,strong) NSString *name;
@property (nonatomic,strong) NSNumber *age;

@end

 NSDictionary *dict = @{@"name": @"张三",@"age":@12}

 People *people = [People new];
  [people setValuesForKeysWithDictionary:dict];

NSLog(@"%@  %d",people.name,people.age);//张三   12

注意事项:如果字典中的键值有id之类的xcode保留值程序就会崩溃,基本数据类行也不识别,解决方法:

//kvc崩溃的话写以下方法
- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{
    if ([key isEqualToString:@"id"]) {//这里的id指的是oc里面的保留字
        self.pID = value;
    }else if ([key isEqualToString:@"pSex"])
    {

//@property (nonatomic,assign) BOOL sex;
        self.sex = [value boolValue];//把对象的值改为基本的数据类型
    }

    NSLog(@"%@ %@",value,key);
}

 kvo:全称是Key-value observing,翻译成键值观察。提供了一种当其它对象属性被修改的时候能通知当前对象的机制。再MVC大行其道的Cocoa中,KVO机制很适合实现model和controller类之间的通讯。

不多说:举例说明

创建一个people类


@interface People : NSObject
@property (nonatomic,strong) NSString *name;
@end

给一个person对象添加观察者

 [_people addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:@"hello"];//NSKeyValueObservingOptionOld,获得旧的值 NSKeyValueObservingOptionNew:获得新的值 

假如我们改变people的name属性,就会触发事件

/*

此方法必须实现,不实现的话系统回报/*
reason: '<ViewController: 0x8e06540>: An -observeValueForKeyPath:ofObject:change:context: message was received but not handled.
错误

*/

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
/*
 keyPath:观察的路径
 object:被观察者
 change:改变的值
 context:对应添加时的context
 */
    NSLog(@"%s",__FUNCTION__);
}

 
 
 
原文地址:https://www.cnblogs.com/hualuoshuijia/p/4998846.html