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 == ===我是俊俊