KVC和KVO

作者: 俊俊吖 | 来源:发表于2017-02-17 17:22 被阅读0次

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

    相关文章

      网友评论

          本文标题:KVC和KVO

          本文链接:https://www.haomeiwen.com/subject/uteiittx.html