Key-Value Coding (KVC) and Generic Programming

61 篇文章 0 订阅

Key-Value Coding (KVC) and Generic Programming

Key-Value Coding (KVC) is a Cocoa protocol for getting and setting values generically. In programming, the term "generically" describes a way of doing things that applies to many different situations.

Generic code can reduce to total amount of code in a project (which is always good) and helps software to handle situations that the programmer didn't anticipate. Generic, reusable code is emphasized throughout Cocoa.

For example, here's a non-generic way to set a first name and last name on an object:


[person setFirstName: @"Scott"];
[person setLastName:  @"Stevenson"];



This works fine, but I can use KVC messages to write more generic code:


[person setValue:@"Scott" forKey:@"firstName"];
[person setValue:@"Stevenson" forKey:@"lastName"];



Beginners might wonder what the point is here. In fact, it actually seems like the KVC version requires more typing. Let's choose another scenario where KVC's value is more apparent.

First, let's define the class:


@interface CDCPerson : NSObject
{
    NSString * firstName;
    NSString * lastName;
    NSNumber * phoneNumber;
    NSString * emailAddress;
}
- (void) setFirstName:    (NSString *)value;
- (void) setLastName:     (NSString *)value;
- (void) setPhoneNumber:  (NSNumber *)value;
- (void) setEmailAddress: (NSString *)value;
@end



Now, some actual code:


// assume inputValues contains values we want to
// set on the person

NSDictionary * inputValues;
CDCPerson    * person = [[CDCPerson alloc] init];
                                  
NSEnumerator *e = [inputValues keyEnumerator];
id dictKey, dictValue;

while ( dictKey = [e nextObject] )

    dictValue = [inputValues valueForKey: dictKey];
    [person setValue: dictValue forKey: dictKey];
}



This snippet of code is generic, meaning that we don't need to change it everytime new instance variables are added to the Person class.

But it gets better! Here's an even simpler version of the code above:


// assume inputValues contains values we want to
// set on the person

NSDictionary * inputValues;
CDCPerson    * person = [[CDCPerson alloc] init];

[person setValuesForKeysWithDictionary: inputValues];



Intrigued? Here's Apple explanation of what's happening in -setValuesForKeysWithDictionary:


Sets properties of the receiver with values from keyedValues, using its keys to identify the properties. The default implementation invokes setValue:forKey: for each key-value pair, substituting nil for NSNull values in keyedValues.



In other words, essentially the same as the first example. But what is -setValue:forKey: actually doing? This is where the KVC magic comes in. It will actually find the -setFirstName:, -setLastName:, -setPhoneNumber: and -setEmailAddress: implementations and call those. If it can't find these, KVC will try quite a few different options before ultimately just setting a value on the instance variable itself.

KVC can also be used to pull values out of an object:


// assume person already exists and is populated with values

CDCPerson * person;

NSMutableDictionary * outputValues;
outputValues = [NSMutableDictionary dictionary];

NSArray * keys;
keys = [NSArray arrayWithObjects: @"firstName",
                                  @"lastName",
                                  @"phoneNumber",
                                  @"emailAddress",
                                  nil];

NSEnumerator *e = [keys objectEnumator];
id key, value;

while ( key = [e nextObject] )

    value = [person valueForKey: key];
    [outputValues setValue: value forKey: key];
}




Or, the simpler version:


// assume person already exists and is populated with values

CDCPerson    * person;
NSArray      * keys;

keys = [NSArray arrayWithObjects: @"firstName",
                                  @"lastName",
                                  @"phoneNumber",
                                  @"emailAddress",
                                  nil];

NSDictionary * outputValues;
outputValues = [person dictionaryWithValuesForKeys: keys];



Just as with setting values, getting values with -valueForKey: will cause KVC to look for a method the same name as the key:


// this will cause KVC to look for a method called -firstName;

NSString * name = [person valueForKey:@"firstName"];



Key-value coding is key element in Cocoa Bindings and Core Data, so it really pays to understand the basic ideas. KVC can handle keypaths, such as:


// getting
[obj valueForKeyPath: @"storage.firstName"];

// setting
[obj setValue: @"Scott" forKeyPath: @"storage.firstName"];



This is similar to doing:


// getting
[[obj storage] firstName];

// setting
[[obj storage] setFirstName:@"Scott"];



For more details on Key-value coding, take a look at this page on ADC.




我自己写了一个demo进行测试,发现dictionaryWithValuesForKeys的功能实在是太强大了,他是自己去寻找合适的函数来进行设置,就算我把设置数据的函数的接口修改成自己都不认识,他还是能够找到,并且设置进去。


这个需要对dictionaryWithValuesForKeys进行进一步的研究了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值