KVC和KVO
之前在对类中的属性进行调用时,往往通过点语法直接就能调用。本节学习一种间接调用对象属性的方法,称它为“KVC”(全称:Key-Value-Coding,键值编码)。
KVC不同于点语法,它是一种间接调取对象属性的方法。它的实现方式是通过字符串来自动找到要更改的对象属性。看一个例子就懂了:
首先创建一个工程,在工程中添加一个类,例如:Person类:
Person.h:
如何通过键值编码的方式间接初始化一个Person类的对象:
main.m:
可以看到,在对person对象初始化后,通过setValue:forKey:的方式给person对象的name、age、sex属性分别赋值。此方法的使用和字典中的setValue:forKey:方法类似,Value和Key必须是对象(两个方法完全没有关系,通过深入框架,可以看到,本节中使用的setValue:forKey:属于NSKeyValueCoding.h接口中提供的方法)。
在使用键值编码对声明的对象进行操作时,Key的值要求和对象中的属性名相同,只有这样才能对对象属性设置成功,否则程序会报告找不到你设置的key,程序出错。
和字典类似,NSKeyValueCoding.h不仅提供了setValue:forKey:的方法对对象中的属性进行设置,还可以通过键值编码的方式来间接地获取到对象中的方法值。可以使用valueForKey:的方法通过key的值来获取对应的属性值:
所以,上个例子中的输出语句,还可以改成:
NSLog(@"The person's name is :%@,and age is :%d, sex is :%d",
[person valueForKey:@"name"],
[[person valueForKey:@"age"] intValue],
[[person valueForKey:@"sex"] boolValue]
);
(由于取出的value是对象,所以还需要转化一下)
除了上边介绍到的KVC提供的方法,NSKeyValueCoding.h接口中还提供了一个方法:
-(void)setValuesForKeysWithDictionary:(NSDictionary<NSString *, id> *)keyedValues;
通过翻译这个方法“用字典通过key设置value”,了解到这同样是一个间接给对象赋值的方法,只不过这个方法需要传入的参数是一个字典。下面,将上面的例子改写一下;
通过不同的方法,最终得到的是一个相同的结果。有两种方式可以实现间接对对象属性赋值的操纵,那么怎么做选择呢?
对于第一种方法,可以在平常方法中使用。而第二种方法,当你从外界文件中读入字典对对象属性进行赋值时,可以极大地减少代码的工作量,提高开发效率。
学习KVO:
和KVC长得很像的,还有一个KVO(全称:Key-Value-Observer,键值观察(或键值监听))
虽然它和KVC就差一个字母,但是它们完全没有关系,本节将它们放在一起,也只是为了初学者能够更好地区分它们。
KVO是干什么的呢?在编程过程中,有时需要对对象的某个或某些属性进行监听,通过对象属性的变化采取相应的对策。
下面来学习一下KVO的具体使用。通过一个例子来具体地感受一下KVO的强大功能
1、创建一个工程,例如Demo;
2、在工程中,创建一个类文件,例如Person
在Person.h文件:
{
kind = 1;
new = LiSi;
old = ZhangSan;
}
{
kind = 1;
new = 20;
old = 10;
}
我们来分析一下main.m文件中代码:
5-7行代码:初始化了一个Person类的对象,并对person对象的属性进行了初始化。
9、10行代码是KVO的重点,通过翻译,我们可以大概了解这个方法的作用,就是给person这个对象添加一个观察者,着个观察者就是自己。那自己观察自己什么呢?要时刻监听name属性值和age属性的变化。options参数的设置是要你选择一但监听的这个name属性值发生了变化,那么你要变化之前的值还是变化之后的值或者是其他类型的值(可以选择多种,可以进入枚举中查看),context可以用来传递数据,没有就设置为nil即可。
12、13行代码:通过直接赋值的方式将person对象的属性的值做了改变。这一步的目的就是要判断监听者能不能监听到数据。
最后一定要移除观察者。(对移除的顺序不做要求)
当我们运行程序的时候打断点会发现,当person对象值发生改变的时候,程序会进入Person.m文件中的那个方法中执行输出语句,这是怎么回事呢?
这就是KVO,当你设置了谁作为监听者之后,监听者所在的类就要实现Perosn.m中的第5行代码,当监听的对象发生变化时,自动调用这个方法,并将变化的数据传递给这个方法的change字典,通过这个字典,我们就可以获取相应的数据。
KVO和通知的关系
相同点:
同属于监听,都能够传递数据。
在程序结束时,都需要移除观察者。
不同点:
KVO比通知更厉害的是,它不仅能够实现监听,同时还能监听对象属性的改变,这是使用通知办不到的。
KVC不同于点语法,它是一种间接调取对象属性的方法。它的实现方式是通过字符串来自动找到要更改的对象属性。看一个例子就懂了:
首先创建一个工程,在工程中添加一个类,例如:Person类:
Person.h:
#import <Foundation/Foundation.h> @interface Person : NSObject @property (nonatomic,copy)NSString * name; @property (nonatomic,assign)int age; @property (nonatomic,assign)int sex; @endPerson.m中没有添加代码。
如何通过键值编码的方式间接初始化一个Person类的对象:
main.m:
#import <Foundation/Foundation.h> #import "Person.h" int main(int argc, const char * argv[]) { Person * person=[[Person alloc] init]; [person setValue:@"ZhangSan" forKey:@"name"]; [person setValue:[NSNumber numberWithInt:10] forKey:@"age"]; [person setValue:[NSNumber numberWithBool:YES] forKey:@"sex"]; NSLog(@"The person's name is :%@,and age is :%d, sex is :%d",person.name,person.age,person.sex); return 0; }输出结果:The person's name is :ZhangSan,and age is :10, sex is :1
可以看到,在对person对象初始化后,通过setValue:forKey:的方式给person对象的name、age、sex属性分别赋值。此方法的使用和字典中的setValue:forKey:方法类似,Value和Key必须是对象(两个方法完全没有关系,通过深入框架,可以看到,本节中使用的setValue:forKey:属于NSKeyValueCoding.h接口中提供的方法)。
在使用键值编码对声明的对象进行操作时,Key的值要求和对象中的属性名相同,只有这样才能对对象属性设置成功,否则程序会报告找不到你设置的key,程序出错。
和字典类似,NSKeyValueCoding.h不仅提供了setValue:forKey:的方法对对象中的属性进行设置,还可以通过键值编码的方式来间接地获取到对象中的方法值。可以使用valueForKey:的方法通过key的值来获取对应的属性值:
所以,上个例子中的输出语句,还可以改成:
NSLog(@"The person's name is :%@,and age is :%d, sex is :%d",
[person valueForKey:@"name"],
[[person valueForKey:@"age"] intValue],
[[person valueForKey:@"sex"] boolValue]
);
(由于取出的value是对象,所以还需要转化一下)
除了上边介绍到的KVC提供的方法,NSKeyValueCoding.h接口中还提供了一个方法:
-(void)setValuesForKeysWithDictionary:(NSDictionary<NSString *, id> *)keyedValues;
通过翻译这个方法“用字典通过key设置value”,了解到这同样是一个间接给对象赋值的方法,只不过这个方法需要传入的参数是一个字典。下面,将上面的例子改写一下;
#import <Foundation/Foundation.h> #import "Person.h" int main(int argc, const char * argv[]) { Person * person=[[Person alloc] init]; NSMutableDictionary * dic=[[NSMutableDictionary alloc]init]; [dic setValue:@"ZhangSan" forKey:@"name"]; [dic setValue:[NSNumber numberWithInt:10] forKey:@"age"]; [dic setValue:[NSNumber numberWithBool:YES] forKey:@"sex"]; [person setValuesForKeysWithDictionary:dic]; NSLog(@"The person's name is :%@,and age is :%d, sex is :%d", [person valueForKey:@"name"], [[person valueForKey:@"age"] intValue], [[person valueForKey:@"sex"] boolValue] ); return 0; }输出结果:The person's name is :ZhangSan,and age is :10, sex is :1
通过不同的方法,最终得到的是一个相同的结果。有两种方式可以实现间接对对象属性赋值的操纵,那么怎么做选择呢?
对于第一种方法,可以在平常方法中使用。而第二种方法,当你从外界文件中读入字典对对象属性进行赋值时,可以极大地减少代码的工作量,提高开发效率。
学习KVO:
和KVC长得很像的,还有一个KVO(全称:Key-Value-Observer,键值观察(或键值监听))
虽然它和KVC就差一个字母,但是它们完全没有关系,本节将它们放在一起,也只是为了初学者能够更好地区分它们。
KVO是干什么的呢?在编程过程中,有时需要对对象的某个或某些属性进行监听,通过对象属性的变化采取相应的对策。
下面来学习一下KVO的具体使用。通过一个例子来具体地感受一下KVO的强大功能
1、创建一个工程,例如Demo;
2、在工程中,创建一个类文件,例如Person
在Person.h文件:
#import <Foundation/Foundation.h> @interface Person : NSObject @property (nonatomic,copy)NSString * name; @property (nonatomic,assign)int age; @end在Person.m文件:
#import "Person.h" @implementation Person -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{ NSLog(@"%@",change); } @end可以发现,在Person.m文件中出现了一个类似和本类毫无关系的对象方法。先不管,先看main.m文件中的代码:
#import <Foundation/Foundation.h> #import "Person.h" int main(int argc, const char * argv[]) { Person * person=[[Person alloc] init]; person.name=@"ZhangSan"; person.age=10; [person addObserver:person forKeyPath:@"name" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil]; [person addObserver:person forKeyPath:@"age" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil]; person.name=@"LiSi"; person.age=20; [person removeObserver:person forKeyPath:@"name" context:nil]; [person removeObserver:person forKeyPath:@"age" context:nil]; return 0; }输出结果:
{
kind = 1;
new = LiSi;
old = ZhangSan;
}
{
kind = 1;
new = 20;
old = 10;
}
我们来分析一下main.m文件中代码:
5-7行代码:初始化了一个Person类的对象,并对person对象的属性进行了初始化。
9、10行代码是KVO的重点,通过翻译,我们可以大概了解这个方法的作用,就是给person这个对象添加一个观察者,着个观察者就是自己。那自己观察自己什么呢?要时刻监听name属性值和age属性的变化。options参数的设置是要你选择一但监听的这个name属性值发生了变化,那么你要变化之前的值还是变化之后的值或者是其他类型的值(可以选择多种,可以进入枚举中查看),context可以用来传递数据,没有就设置为nil即可。
12、13行代码:通过直接赋值的方式将person对象的属性的值做了改变。这一步的目的就是要判断监听者能不能监听到数据。
最后一定要移除观察者。(对移除的顺序不做要求)
当我们运行程序的时候打断点会发现,当person对象值发生改变的时候,程序会进入Person.m文件中的那个方法中执行输出语句,这是怎么回事呢?
这就是KVO,当你设置了谁作为监听者之后,监听者所在的类就要实现Perosn.m中的第5行代码,当监听的对象发生变化时,自动调用这个方法,并将变化的数据传递给这个方法的change字典,通过这个字典,我们就可以获取相应的数据。
KVO和通知的关系
相同点:
同属于监听,都能够传递数据。
在程序结束时,都需要移除观察者。
不同点:
KVO比通知更厉害的是,它不仅能够实现监听,同时还能监听对象属性的改变,这是使用通知办不到的。