IOS KVC 机制

来源:互联网 发布:西安汇知中学教师招聘 编辑:程序博客网 时间:2024/05/16 16:21
一 KVC简介

       IOS 的运行时十分的强大,利用它可以实现好多的功能,例如 可以在程序运行期间通过一个类的对象来获取其类对象,调用函数的时候引 发的消息传递,以及KVC机制的实现等等。
       KVC,即:Key-value coding,它是一种使用字符串标识符,间接访问对象属性的机制,它是KVO,Core Data等很多技术的基础。主要的方法就两个,setValue:forKey,valueForKey。所用从NSObject继承的类都实现了NSKeyValueCoding。

二 使用方法

先看一段代码:
@interface BookData :NSObject
{
   
 NSString *bookName;
   
 NSString *bookAuthor;
}

@end

 BookData *bookdata = [[BookData alloc] init];
[bookdata
 setValue:@"Hello" forKey:@"bookName"];
[bookdata
 setValue:@"Lucy" forKey:@"bookAuthor"];
NSLog(@"%@   %@",[bookdata valueForKey:@"bookName"],[bookdata valueForKey:@"bookAuthor"]);

   首先定义了一个BookData类,包含两个属性bookName和bookAuthor,注意我没有定义存期器方法,接着在使用的时候我用的KVC机制可以通过它们属性的名称来简介的访问BookData对象的属性。


注意:1.属性名称是区分大小写,如果像下面这样来写:
      [bookdata setValue:@"Hello" forKey:@"BookName"];
    此时因为找不到名称是BookNamed的属性变量,程序会抛出NSUnknownKeyException异常,我们可以在类内重载NSKeyValueCoding中的- (void) setValue:(id)value forUndefinedKey:(NSString *)key 方法来捕获异常,从而避免程序因错退出。
    同理,如果valueForKey中的键不存在的话,也会有异常,我们可以重载- (id)valueForUndefinedKey:(NSString *)key方法。最后修改后的代码如下:

@interface BookData :NSObject
{
   
 NSString *bookName;
   
 NSString *bookAuthor;
}
@end
@implementation BookData

- (void) setValue:(id)value forUndefinedKey:(NSString *)key
{
   
 NSLog(@"Not Found Key:%@",key);
}

- (
id)valueForUndefinedKey:(NSString *)key
{
   
   
 return @"Not Found!";
}
@end

    2.如果要存取BookData内部对象的属性则需要使用 setValue:forKeyPath:和valueForKeyPath,看下面的实例代码:

@class Address;
@interface BookData :NSObject
{
   
 NSString *bookName;
   
 NSString *bookAuthor;
   
 Address  *address;
}
@end
@implementation BookData

- (
void) setValue:(id)value forUndefinedKey:(NSString *)key
{
   
 NSLog(@"Not Found Key:%@",key);
}

- (
id)valueForUndefinedKey:(NSString *)key
{
   
   
 return @"Not Found!";
}
@end


@interface Address : NSObject
{
   
 NSString *province;
   
 NSString *city;
}

@end
@implementation Address
@end

在程序中添加了,Address作为BookData的对象成员,下面来使用KVC为BookData的成员变量address来赋值并取值输出:
    Address *address = [[Address alloc] init];
   
 BookData *bookdata = [[BookData alloc] init];
    [bookdata
 setValue:@"Hello" forKey:@"bookName"];
    [bookdata
 setValue:@"Lucy" forKey:@"bookAuthor"];
   
    [bookdata
 setValue:address  forKey:@"address"];
    [bookdata
 setValue:@"Hebei" forKeyPath:@"address.province"]; //使用forKeyPath来赋值
   
   
 NSLog(@"%@   %@   %@",[bookdata valueForKey:@"bookName"],[bookdata valueForKey:@"bookAuthor"],[bookdata valueForKeyPath:@"address.province"]); //使用valueForKeyPath来取值
}

三 总结
 
  下面简单来说一下KVC的实现原理。

 1. setValue:forKey的搜索方式:
      首先搜索set<Key>:方法
      如果成员用@property,@synthsize处理,因为@synthsize告诉编译器自动生成set<Key>:格式的setter方法,所以这种情况下会直接搜索到。 注意:这里的<Key>是指成员名,而且首字母大写(必须大写,否则找不到)。
       然后搜索成员名
     上面的setter方法没有找到,如果类方法accessInstanceVariablesDirectly返回YES(注:这是NSKeyValueCodingCatogery中实现的类方法,默认实现为返回YES)。 那么按_<key>,_is<Key>,<key>,is<key>的顺序搜索成员名。注意:这里是区分大小写的。 如果找到设置成员的值
        最后没有找到
  调用setValue:forUndefinedKey:
2.valueForKey:的搜索方式
    首先搜索get<Key>  <key>  is<key>方法
    按get<Key> <key> is<Key> 的顺序查找getter方法 找到直接调用 如果是bool int 等内建值类型 会做NSNumber的转换 
      注意:
      1.get<Key>和is<Key>中的key首字母大写  而<key>中的和属性名字保持一致。
      2.上面的getter没有找到 查找countOf<Key> objectIn< Key>AtIndex < Key>AtIndexes 格式的方法 如果countOf<Key>和另外两个方法中的一个找到 那么就会返回一个可以响应NSArray所有方法的代理集合 collection proxy object 发送给这个代理集合 collection proxy object 的NSArray消息方法 就会以countOf<Key> objectIn< Key>AtIndex < Key>AtIndexes 这几个方法组合的形式调用 还有一个可选的get<Key> range 方法 
      3 还没查到 那么查找countOf<Key> enumeratorOf<Key > memberOf<Key > 格式的方法 如果这三个方法都找到 那么就返回一个可以响应NSSet所有方法的代理集合 collection proxy object 发送给这个代理集合 collection proxy object 的NSSet消息方法 就会以countOf<Key> enumeratorOf<Key > memberOf<Key > 组合的形式调用 
    搜索成员变量
        那么如果类方法accessInstanceVariablesDirectly返回YES 那么按 _< key > _is<Key > < key > is<key> 的顺序直接搜索成员名 
    最后没找到 
      调用valueForUndefinedKey