KVC KVO

   看了一天的KVC、KVO,我就把网上的资料整理一下吧,如有雷同的地方,勿惊。
   1、 KVC
   KVC :NSKeyValueCoding的简称,它提供了一种在运行时而非编译时动态访问对象属性与成员变量的方式,也就是说,我们可以用字符串的内容作为属性名称或者成员变量名    称进行访问。这种特性有些类似于其他高级编程语言中的反射。
   
   主要的方法
  (setValue:forKey,valueForKey)、setValue:forKeyPath,valueForKeyPath)、setValue: forUndefinedKey:


   KVC使用实例


   1)简单的存取值
   .h文件
   #import <Foundation/Foundation.h>
   @interface Student : NSObject {
        NSString *name;
   }
   @end


   .m文件
   #import "Student.h"
   @implementation Student


   @end


   通过kvc实现值的存取操作 ps:绕开了property属性访问机制
   #import "Student.h"
    int main(int argc, const char * argv[])
   {
       @autoreleasepool {
           Student *student = [[[Student alloc]init ]autorelease];
           [student setValue:@"张三" forKey:@"name"];
           NSString *name = [student valueForKey:@"name"];
           NSLog(@"学生姓名:%@",name);
       }
       return 0;
   }
   
   2)通过键路径访问属性
   如果要访问一个类中属性的属性呢???看下面例子
   .h文件
   #import <Foundation/Foundation.h>
   @interface Course : NSObject {
       NSString *CourseName;
   }
   @end
   
   .m文件
   #import "Course.h"
   @implementation Course


   @end


   在Student中添加Course属性 ,student.h文件中代码如下:
   #import <Foundation/Foundation.h>
   @class Course;
   @interface Student : NSObject {
       NSString *name;
       Course *course;
   }
   @end


   student.m文件中依然什么都没有实现


   在main方法中,我们实验通过键路径访问Course中CourseName的属性
   #import "Student.h"
   #import "Course.h"


   int main(int argc, const char * argv[])
   {
       @autoreleasepool {
           Student *student = [[[Student alloc]init ]autorelease];
           [student setValue:@"张三" forKey:@"name"];
           NSString *name = [student valueForKey:@"name"];
           NSLog(@"学生姓名:%@",name);
        
           Course *course = [[[Course alloc]init] autorelease];
           [course setValue:@"语文课" forKey:@"CourseName"];
           [student setValue:course forKey:@"course"];
           NSString *courseName = [student valueForKeyPath:@"course.CourseName"];
           NSLog(@"课程名称:%@", courseName);
        
           //也可以这样存值
           [student setValue:@"数学课" forKeyPath:@"course.CourseName"];
           courseName = [student valueForKeyPath:@"course.CourseName"];
           NSLog(@"课程名称:%@", courseName);
        
       }
       return 0;
   }


   3)操作集合
   在Student类中加入数组NSArray,用来表示其他的学生。这样我们可以添加多个其他的学生,再用集合操作计算学生的分数,最高分,最低分,平均分等
   #import <Foundation/Foundation.h>
   @class Course;
   @interface Student : NSObject
   {
       NSString *name;
       Course *course;
       NSInteger point;
       NSArray *otherStudent;
   }
   @end
 
   .m文件实现不变


   在main函数中添加三个学生,添加到数组中,然后求平均分,最高,最低分,学生数量
   #import "Student.h"
   #import "Course.h"


   int main(int argc, const char * argv[])
   {
       @autoreleasepool {
           Student *student = [[[Student alloc]init ]autorelease];
           [student setValue:@"张三" forKey:@"name"];
           NSString *name = [student valueForKey:@"name"];
           NSLog(@"学生姓名:%@",name);
        
           [student setValue:@"88" forKey:@"point"];
           NSString *point = [student valueForKey:@"point"];
           NSLog(@"分数:%@", point);
        
           Student *student1 = [[[Student alloc]init]autorelease];
           Student *student2 = [[[Student alloc]init]autorelease];
           Student *student3 = [[[Student alloc]init]autorelease];
           [student1 setValue:@"65" forKey:@"point"];
           [student2 setValue:@"77" forKey:@"point"];
           [student3 setValue:@"99" forKey:@"point"];
           NSArray *array = [NSArray arrayWithObjects:student1,student2,student3,nil];
           [student setValue:array forKey:@"otherStudent"];
           NSLog(@"其他学生的成绩%@", [student valueForKeyPath:@"otherStudent.point"]);
           NSLog(@"共%@个学生", [student valueForKeyPath:@"otherStudent.@count"]);
           NSLog(@"最高成绩:%@", [student valueForKeyPath:@"otherStudent.@max.point"]);
           NSLog(@"最低成绩:%@", [student valueForKeyPath:@"otherStudent.@min.point"]);
           NSLog(@"平均成绩:%@", [student valueForKeyPath:@"otherStudent.@avg.point"]);
       }
       return 0;
   }


   KVC的优点
   使用KVC可以大大地减少我们的代码量,当遇到property的时候,可以多想想是否可以KVC来帮助我,是否可以用KVC来重构代码


   关于KVC的使用,附上一个很好的文章,相信对你重代码会有很大帮助
   http://www.cocoachina.com/industry/20140224/7866.html


   2、 KVO
   KVO :NSKeyValueObserving, 它是一种观察者模式用于监听property的变化,KVO跟NSNotification有很多相似的地方。


   KVO使用实例
   当指定的对象的属性被修改了,允许对象接收到通知的机制。每当在类中定义一个监听
   如: [self addObserver:self forKeyPath:@"items" options:0 context:contexStr];
   当然你还可以监听其他对象的属性变化 
   [person addObserver:money forKeyPath:@"account" options:0 context:contexStr];
   只要当前类中items这个属性发生的变化都会触发到以下的方法。
   - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object 
    change:(NSDictionary *)change context:(void *)context


   KVO的优点
   当 有属性改变,KVO会提供自动的消息通知。这样的架构有很多好处。首先,开发人员不需要自己去实现这样的方案:每次属性改变了就发送消息通知。这是KVO机制提供的最     大的优点。因为这个方案已经被明确定义,获得框架级支持,可以方便地采用。开发人员不需要添加任何代码,不需要设计自己的观察者模型,直接可以在工程里使用。其次,KV   O的架构非常的强大,可以很容易的支持多个观察者观察同一个属性,以及相关的值。


  3、关于KVC和KVO 


   KVC的实现分析


   KVC运用了一个isa-swizzling技术。
   isa-swizzling就是类型混合指针机制。KVC主要通过isa-swizzling,来实现其内部查找定位的。
   isa指针,就是is a kind of的意思,指向维护分发表的对象的类。该分发表实际上包含了指向实现类中的方法的指针,和其它数据。


   如下KVC的代码:


   [person setValue:@"personName" forKey:@"name"];


   就会被编译器处理成:


   SEL sel = sel_get_uid ("setValue:forKey:");


   IMP method = objc_msg_lookup (person->isa,sel);


   method(person, sel, @"personName", @"name");


   ***


   其中:


   SEL数据类型:它是编译器运行Objective-C里的方法的环境参数。


   IMP数据类型:他其实就是一个 编译器内部实现时候的函数指针。当Objective-C编译器去处理实现一个方法的时候,就会指向一个IMP对象,这个对象是C语言表述的类型。


   ***


   KVC在调用方法setValue的时候
   1)首先根据方法名找到运行方法的时候所需要的环境参数。
   2)他会从自己isa指针结合环境参数,找到具体的方法实现的接口。
   3)再直接查找得来的具体的方法实现。


   这样的话前面介绍的KVO实现就好理解了


   当一个对象注册了一个观察者,被观察对象的isa指针被修改的时候,isa指针就会指向一个中间类,而不是真实的类。


   所以isa指针其实不需要指向实例对象真实的类。所以我们的程序最好不要依赖于isa指针。在调用类的方法的时候,最好要明确对象实例的类名。


   这样只有当我们调用KVC去访问key值的时候KVO才会起作用。所以肯定确定的是,KVO是基于KVC实现的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值