objectForKey和valueForKey的区别?

objectForKeyvalueForKey有什么区别? 我在文档中查阅了两者,在我看来是一样的。

114009 次浏览

当你执行valueForKey:时,你需要给它一个NSString,而objectForKey:可以接受任何NSObject子类作为键。这是因为对于键值编码,键总是字符串。

事实上,文档指出,即使你给valueForKey:一个NSString,它也会调用objectForKey:,除非字符串以@开头,在这种情况下,它会调用[super valueForKey:],而[super valueForKey:]可能会调用valueForUndefinedKey:,从而引发异常。

objectForKey:是一个NSDictionary方法。NSDictionary是一个类似于NSArray的集合类,除了它不使用索引,而是使用键来区分项。键是您提供的任意字符串。没有两个对象可以有相同的键(就像NSArray中没有两个对象可以有相同的索引一样)。

valueForKey:是一个KVC方法。它适用于任何类。valueForKey:允许你使用字符串作为属性名来访问属性。例如,如果我有一个Account类,其属性为accountNumber,我可以执行以下操作:

NSNumber *anAccountNumber = [NSNumber numberWithInt:12345];
Account *newAccount = [[Account alloc] init];


[newAccount setAccountNumber:anAccountNUmber];


NSNumber *anotherAccountNumber = [newAccount accountNumber];

使用KVC,我可以动态访问属性:

NSNumber *anAccountNumber = [NSNumber numberWithInt:12345];
Account *newAccount = [[Account alloc] init];


[newAccount setValue:anAccountNumber forKey:@"accountNumber"];


NSNumber *anotherAccountNumber = [newAccount valueForKey:@"accountNumber"];

它们是等价的表述。

我知道你在想:哇,但讽刺的是。KVC看起来没那么有用。事实上,它看起来很“啰嗦”。但是当你想在运行时改变一些东西时,你可以做很多很酷的事情,这些事情在其他语言中要困难得多(但这超出了你的问题范围)。

如果你想了解更多关于KVC的知识,有很多教程,特别是在斯科特·史蒂文森的博客。你也可以检查NSKeyValueCoding协议引用

希望这能有所帮助。

这是尽可能使用objectForKey:而不是valueForKey:的一个很好的理由——带有未知键的valueForKey:将抛出NSUnknownKeyException,表示“这个类不符合键的键值编码”。

如上所述,objectForKey:数据类型是:(id)aKey,而valueForKey:数据类型是:(NSString *)key

例如:

 NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSArray arrayWithObject:@"123"],[NSNumber numberWithInteger:5], nil];


NSLog(@"objectForKey : --- %@",[dict objectForKey:[NSNumber numberWithInteger:5]]);
//This will work fine and prints (    123    )


NSLog(@"valueForKey  : --- %@",[dict valueForKey:[NSNumber numberWithInteger:5]]);
//it gives warning "Incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString *'"   ---- This will crash on runtime.

因此,valueForKey:将只接受一个字符串值,并且是一个KVC方法,而objectForKey:将接受任何类型的对象。

objectForKey中的值将被同一类型的对象访问。

我将在这里提供一个全面的答案。大部分观点出现在其他答案中,但我发现每个答案都不完整,有些不正确。

首先,objectForKey:是一个NSDictionary方法,而valueForKey:是任何KVC投诉类所需的KVC协议方法——包括NSDictionary。

此外,正如@dreamlax所写的,文档提示NSDictionary实现了它的valueForKey:方法使用实现了它的objectForKey:实现。换句话说——[NSDictionary valueForKey:]调用[NSDictionary objectForKey:]

这意味着,valueForKey:永远不会比objectForKey:快(在相同的输入键上),尽管我所做的彻底测试表明,在对一个巨大的NSDictionary的数十亿次随机访问中,大约有5%到15%的差异。在正常情况下,差异可以忽略不计。

接下来:KVC协议只适用于NSString *键,因此valueForKey:将只接受NSString *(或子类)作为键,而NSDictionary可以将其他类型的对象作为键-因此“较低级别”objectForKey:接受任何可复制(NSCopying协议兼容)对象作为键。

最后,valueForKey:NSDictionary's实现偏离了KVC文档中定义的标准行为,并且不会为它找不到的键发出NSUnknownKeyException -除非这是一个“特殊”键-一个以“@”开头的键-通常意味着一个“聚合”函数键(例如@"@sum, @"@avg")。相反,当在NSDictionary中没有找到键时,它将简单地返回nil -行为与objectForKey:相同

下面是演示和证明我的笔记的一些测试代码。

- (void) dictionaryAccess {
NSLog(@"Value for Z:%@", [@{@"X":@(10), @"Y":@(20)} valueForKey:@"Z"]); // prints "Value for Z:(null)"


uint32_t testItemsCount = 1000000;
// create huge dictionary of numbers
NSMutableDictionary *d = [NSMutableDictionary dictionaryWithCapacity:testItemsCount];
for (long i=0; i<testItemsCount; ++i) {
// make new random key value pair:
NSString *key = [NSString stringWithFormat:@"K_%u",arc4random_uniform(testItemsCount)];
NSNumber *value = @(arc4random_uniform(testItemsCount));
[d setObject:value forKey:key];
}
// create huge set of random keys for testing.
NSMutableArray *keys = [NSMutableArray arrayWithCapacity:testItemsCount];
for (long i=0; i<testItemsCount; ++i) {
NSString *key = [NSString stringWithFormat:@"K_%u",arc4random_uniform(testItemsCount)];
[keys addObject:key];
}


NSDictionary *dict = [d copy];
NSTimeInterval vtotal = 0.0, ototal = 0.0;


NSDate *start;
NSTimeInterval elapsed;


for (int i = 0; i<10; i++) {


start = [NSDate date];
for (NSString *key in keys) {
id value = [dict valueForKey:key];
}
elapsed = [[NSDate date] timeIntervalSinceDate:start];
vtotal+=elapsed;
NSLog (@"reading %lu values off dictionary via valueForKey took: %10.4f seconds", keys.count, elapsed);


start = [NSDate date];
for (NSString *key in keys) {
id obj = [dict objectForKey:key];
}
elapsed = [[NSDate date] timeIntervalSinceDate:start];
ototal+=elapsed;
NSLog (@"reading %lu objects off dictionary via objectForKey took: %10.4f seconds", keys.count, elapsed);
}


NSString *slower = (vtotal > ototal) ? @"valueForKey" : @"objectForKey";
NSString *faster = (vtotal > ototal) ? @"objectForKey" : @"valueForKey";
NSLog (@"%@ takes %3.1f percent longer then %@", slower, 100.0 * ABS(vtotal-ototal) / MAX(ototal,vtotal), faster);
}

该表表示objectForKeyvalueForKey之间的四个差异。

objectForKey valueForKey
工作在…… NSDictionary NSDictionary / KVC
抛出异常 没有 是的(KVC)
饲料 NSObject的子类 NSString
在KVC上使用 不能 可以