gavanwanggw

导航

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机制提供的最     大的优点。

由于这个方法已经被明白定义,获得框架级支持,能够方便地採用。

开发者不须要加入不论什么代码。不须要设计自己的观察者模型,直接能够在project里使用。其次,KV   O的架构非常的强大,能够非常easy的支持多个观察者观察同一个属性,以及相关的值。


  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实现的。

posted on 2017-08-05 09:21  gavanwanggw  阅读(162)  评论(0编辑  收藏  举报