IOS KVC(键值编码)模式

    在IOS的中,没有绝对的私有,包括方法和变量。私有方法通过类实例无法直接访问,但因为有"编译时运行"机制,我们可以通过类似perfromSelectoe的方法来访问私有方法。而IOS中的私有变量通过所谓的KVC模式也是可以访问的。下面特酷吧整理了IOS KVC模式的使用方法。
    KVC模式就是key-value coding(键值编码),它的原理是使用字符串标识,间接访问对象属性。关键方法在NSKeyValueCodingprotocol中定义。KVC支持类对象和内建基本数据类型。我们主要使用到它的两对方法:
1,setValue:forKey,valueForKey;传入NSString属性的名字
2,setValue:forKeyPath,valueForKeyPath(传入NSString属性的路径,xx.xx形式)
需要注意:
当通过KVC调用对象时,比如:[self valueForKey:@"tekuba"];
程序会自动试图通过几种不同的方式解析这个调用。首先查找对象是否带有tekuba这个方法以及getTekuba,_tekuba以及_getTekuba这几种形式,如果没找到,会继续查找对象是否带有tekuba这个实例变量(iVar),如果还没有找到,程序会继续试图调用 -(id) valueForUndefinedKey:这个方法。如果这个方法还是没有被实现的话,程序会抛出一个NSUndefinedKeyException异常错误(待确认)。
设计valueForUndefinedKey:方法的主要目的是当你使用-(id)valueForKey方法从对象中请求值时,对象能够在错误发生前,有最后的机会响应这个请求
请看下面的示例:

头文件TekubaNet.h

#import
@interface TekubaNet:NSObject
{
    NSString *url;
}
@end
实现文件

#import"TekubaNet.h"
@implementation TekubaNet
@end
这个TekubaNet类很简单,只有一个url变量。这种情况我们是没有办法通过TekubaNet的类实例访问url的。
下面我们使用KVC模式访问url。如下:

int main (int argc, const char * argv[]) {  
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];  
    TekubaNet *tekubaNet=[[TekubaNet alloc] init];  
    [tekubaNet setValue:@"http://www.tekuba.net" forKey:@"url"];  
    NSString *url=[book valueForKey:@"url"];  
    NSLog(@"tekuba url= %@",url);  
    [pool release];  
    return 0;  
}  
下面我们对代码做一些补充:
定义一个Webmaster类,特酷吧的博主:
头文件Webmaster.h
#import
@interface Webmaster:NSObject
{
    NSString *name;
}
@end
实现文件

#import"Webmaster.h"
@implementation Webmaster
@end
将Webmaster添加到TekubaNet类,如下:

#import
@interface TekubaNet:NSObject
{
    Webmaster *webmaster;
    NSString *url;
}
@end
TekubaNet的实现文件不变。
下面演示使用KVC模式访问TekubaNet中webmaster的name属性。
int main (int argc, const char * argv[]) {  
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];  
    TekubaNet *tekubaNet=[[[TekubaNet alloc] init] autorelease];  
    [tekubaNet setValue:@"http://www.tekuba.net" forKey:@"url"];  
    NSString *url=[tekubaNet valueForKey:@"url"];  
    NSLog(@"tekuba url: %@",url);  
    Webmaster *webmaster=[[[Webmaster alloc] init] autorelease];  
    [webmaster setValue:@"特酷吧" forKey:@"name"];  
    [tekubaNet setValue:webmaster forKey:@"webmaster"];  
    NSString *name=[tekubaNet valueForKeyPath:@"webmaster.name"]; /*在IOS中这种方式叫path*/  
    NSLog(@"webmaster name: %@",name);  
    [pool release];  
    return 0;  
}  
另外需要注意,KVC还有一个重要的特点就是自动装箱拆箱功能:即KVC会根据字符串自动的转型成适当的数据类型,例如:

@interface TekubaNet:NSObject
{
    Webmaster *webmaster;
    NSString *url;
    int runDay;
}
则我们还是可以通过之前的方式访问:
[tekubaNet setValue:@"365" forKey:@"runDay"]; 
NSLog(@"tekubaNet runTime is %@",[tekubaNet valueForKey:@"runDay"]); 
虽然runDay是int型的,但我们一样可以通过%@打印。
(1)setValue:forKey的搜索方式:
首先搜索set:方法。如果成员用@property,@synthsize处理,因为@synthsize告诉编译器自动生成set:格式的setter方法,所以这种情况下会直接搜索到。注意:这里的是指成员名,而且首字母大写。下同。
上面的setter方法没有找到,如果类方法accessInstanceVariablesDirectly返回YES(注:这是NSKeyValueCodingCatogery中实现的类方法,默认实现为返回YES)。那么按_,_is,is的顺序搜索成员名。
如果找到设置成员的值,如果没有调用setValue:forUndefinedKey:。
(2)valueForKey:的搜索方式:
1. 首先按get、is的顺序查找getter方法,找到直接调用。如果是bool、int等内建值类型,会做NSNumber的转换。
2. 上面的getter没有找到,查找countOf、objectInAtIndex:、AtIndexes格式的方法。
如果countOf和另外两个方法中的一个找到,那么就会返回一个可以响应NSArray所有方法的代理集合(collection proxy object)。发送给这个代理集合(collection proxy object)的NSArray消息方法,就会以countOf、objectInAtIndex:、AtIndexes这几个方法组合的形式调用。还有一个可选的get:range:方法。
3. 还没查到,那么查找countOf、enumeratorOf、memberOf:格式的方法。
如果这三个方法都找到,那么就返回一个可以响应NSSet所有方法的代理集合(collection proxy object)。发送给这个代理集合(collection proxy object)的NSSet消息方法,就会以countOf、enumeratorOf、memberOf:组合的形式调用。
4. 还是没查到,那么如果类方法accessInstanceVariablesDirectly返回YES,那么按_,_is,is的顺序直接搜索成员名。
5. 再没查到,调用valueForUndefinedKey:。

来自特酷吧,本文地址:www.tekuba.net/program/294/

你可能感兴趣的:(iOS,SDK)