KVC和KVO都属于键值编程而且底层实现机制都是isa-swizzing
一.KVC概述
1.kvc 是一种通过(key)来访问类属性的机制,而不是通过 set get 方法。
2.关键方法定义在NskeyValueCodingProtocol
kvc 支持类对象,和基本数据类型
二。
KVC使用
举一个例子:
我创建一个类:
@interface Pperson :NSObject
@end
@implementation Pperson
-(NSString*)description{
return[NSStringstringWithFormat:@"PPdescrpation<%@:%p>,{name:%@,age:%d}",[selfclass],self,self.name,self.age];
}
@end
@implementationViewController
-(void)aboutPperson{
Pperson*p1 = [[Ppersonalloc]init];
[p1setValue:@"junjun"forKey:@"name"];
[p1setValue:@"26"forKey:@"age"];
Pperson*p2 = [[Ppersonalloc]init];
[p2setValue:@"junjun1"forKey:@"name"];
[p2setValue:@"27"forKey:@"age"];
NSLog(@"p1=====%@,p2.name====%@",p1,[p2valueForKeyPath:@"name"]);
NSArray*arr =@[p1,p2];
///可以通过路径直接找到属性的值无论怎么嵌套属性
NSLog(@"arr的name===%@",[arrvalueForKeyPath:@"name"]);
}
运行结果:p1=====PPdescrpation,{name:junjun,age:26},p2.name====junjun1
2017-02-17 10:57:46.471 NewCocoTest[1063:47085] arr的name===(
junjun,
junjun1
)
我把Pperson两个属性改为在.m里面
@interfacePperson(){
NSString*name;
int age;
}
@end
@implementationPperson
-(NSString*)description{
return[NSStringstringWithFormat:@"PPdescrpation<%@:%p>,{name:%@,age:%d}",[selfclass],self,name,age];
}
//运行结果如下:
p1=====PPdescrpation,{name:junjun,age:26},p2.name====junjun1
2017-02-17 10:47:44.601 NewCocoTest[1012:40918] arr的name===(
junjun,
junjun1
)
两次的运行结果是一样的,所以说 KVC 不是调用的set get 方法,还有KVC 可以层层深入直接找到属性的值。把代码,[arrvalueForKeyPath:@"name"]换成[arrvalueForKey:@"name"]也是可以的
再创建一个类作为Pperson类的变量
@interfaceCourseModel(){
NSString*_coursename;
}
@end
@implementationCourseModel
-(NSString*)description{
return[NSStringstringWithFormat:@"coursename=====%@",_coursename];
}
-(void)aboutPperson{
Pperson*p1 = [[Ppersonalloc]init];
CourseModel*course1 = [[CourseModelalloc]init];
[course1setValue:@"语文课"forKey:@"coursename"];
[p1setValue:@"junjun"forKey:@"name"];
[p1setValue:@"26"forKey:@"age"];
[p1setValue:course1forKey:@"course"];
//NSString *name1 = [p1 valueForKeyPath:@"course.coursename"];
Pperson*p2 = [[Ppersonalloc]init];
[p2setValue:@"junjun1"forKey:@"name"];
[p2setValue:@"27"forKey:@"age"];
CourseModel*course2 = [[CourseModelalloc]init];
[course2setValue:@"数学课"forKey:@"coursename"];
[p2setValue:course2forKey:@"course"];
NSLog(@"p1=====%@,p2.name====%@",p1,p2);
NSArray*arr =@[p1,p2];
NSArray*namearr = [[arrvalueForKeyPath:@"course"]valueForKeyPath:@"coursename"];
for(inti =0; i < namearr.count; i++) {
UILabel*label = [[UILabelalloc]init];
label.text= namearr[i];
label.frame=CGRectMake(i*100,100,100,30);
label.backgroundColor= [UIColorredColor];
[self.viewaddSubview:label];
}
}
运行结果如下:
p1=====PPdescrpation,{name:junjun,age:26,course:coursename=====语文课},p2.name====PPdescrpation,{name:junjun1,age:27,course:coursename=====数学课}
@end
因此证明了一个道理:KVC可以一层一层的深入寻找属性的值。我们用NSString*类型设置的属性值@"26",而我们的属性是NSInteger类型的,存取都没有问题。
我又加了一个数组在PPerson类里面
@interfacePperson(){
NSString*name;
intage;
CourseModel*course;
NSArray*otherStudent;//其他学生
}
-(void)aboutPperson{
Pperson*p = [[Ppersonalloc]init];
[psetValue:@"45"forKey:@"age"];
Pperson*p1 = [[Ppersonalloc]init];
CourseModel*course1 = [[CourseModelalloc]init];
[course1setValue:@"语文课"forKey:@"coursename"];
[p1setValue:@"junjun"forKey:@"name"];
[p1setValue:@"26"forKey:@"age"];
[p1setValue:course1forKey:@"course"];
//NSString *name1 = [p1 valueForKeyPath:@"course.coursename"];
Pperson*p2 = [[Ppersonalloc]init];
[p2setValue:@"junjun1"forKey:@"name"];
[p2setValue:@"27"forKey:@"age"];
CourseModel*course2 = [[CourseModelalloc]init];
[course2setValue:@"数学课"forKey:@"coursename"];
[p2setValue:course2forKey:@"course"];
NSLog(@"p1=====%@,p2.name====%@",p1,p2);
NSArray*arr =@[p1,p2];
NSArray*namearr = [arrvalueForKeyPath:@"course.coursename"];
//[[arrvalueForKeyPath:@"course"] valueForKeyPath:@"coursename"];//或者
for(inti =0; i < namearr.count; i++) {
UILabel*label = [[UILabelalloc]init];
label.text= namearr[i];
label.frame=CGRectMake(i*100,100,100,30);
label.backgroundColor= [UIColorredColor];
[self.viewaddSubview:label];
}
NSArray*arryother = [[NSArrayalloc]initWithObjects:p1,p2,nil];
[psetValue:arryotherforKey:@"otherStudent"];
NSLog(@"其他学生的分数%@",[pvalueForKeyPath:@"otherStudent.age"]);//valueForKeyPath:@"age"]);
NSLog(@"最大年龄%@",[pvalueForKeyPath:@"otherStudent.@max.age"] );
NSLog(@"最小年龄%@",[pvalueForKeyPath:@"otherStudent.@min.age"] );
NSLog(@"年龄的平均值%@",[pvalueForKeyPath:@"otherStudent.@avg.age"]);
}
//运行结果如下:NewCocoTest[1992:130252]其他学生的分数(
26,
27
)
2017-02-17 15:01:54.655 NewCocoTest[1992:130252]最大年龄27
2017-02-17 15:01:54.655 NewCocoTest[1992:130252]最小年龄26
2017-02-17 15:01:54.655 NewCocoTest[1992:130252]年龄的平均值26.5
KVO的是KeyValue Observe的缩写,这是一个典型的观察者模式,观察者在键值改变时会得到通知。iOS中有个Notification的机制,也可以获得通知,但这个机制需要有个Center,相比之下KVO更加简洁而直接。
KVO的使用也很简单,就是简单的3步。
1.注册需要观察的对象的属性addObserver:forKeyPath:options:context:
2.实现observeValueForKeyPath:ofObject:change:context:方法,这个方法当观察的属性变化时会自动调用
3.取消注册观察removeObserver:forKeyPath:context:
举一个简单的例子:
@interfacetestMyPerson :NSObject{
NSString*testMyPersonName;
}
@end
在控制器里调用这个方法
-(void)testKVO{
self.testPeron= [[testMyPersonalloc]init];
[self.testPeronaddObserver:selfforKeyPath:@"testMyPersonName"options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOldcontext:nil];
}
-(void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void*)context{
if([keyPathisEqualToString:@"testMyPersonName"]) {
NSLog(@"new=====%@",[changevalueForKey:NSKeyValueChangeNewKey]);
}else{
}
}
-(void)Uiconfig{
self.title=@"第二个控制器";
UIButton*button = [[UIButtonalloc]init];
[self.viewaddSubview:button];
button.frame=CGRectMake(0,64,100,30);
[buttonsetTitle:@"高度变化"forState:UIControlStateNormal];
[buttonsetTitleColor:[UIColorredColor]forState:UIControlStateNormal];
[buttonaddTarget:selfaction:@selector(changeHeight:)forControlEvents:UIControlEventTouchUpInside];
}
-(void)changeHeight:(UIButton*)button{
NSString*height = [self.testPeronvalueForKey:@"testMyPersonName"] ;
[self.testPeronsetValue:@"我是俊俊"forKey:@"testMyPersonName"];
NSLog(@"testMyPersonNameName == ===%@",[self.testPeronvalueForKeyPath:@"testMyPersonName"]);
}
当属性值无论会不会改变都会调用一遍监听方法,
NewCocoTest[3097:194495] new=====我是俊俊
2017-02-17 17:08:15.560 NewCocoTest[3097:194495] testMyPersonNameName == ===我是俊俊
2017-02-17 17:08:22.140 NewCocoTest[3097:194495] new=====我是俊俊
2017-02-17 17:08:34.438 NewCocoTest[3097:194495] testMyPersonNameName == ===我是俊俊
网友评论