objectForKey
和valueForKey
有什么区别?我在文档中都对它们进行了查找,对我来说它们似乎相同。
#1 楼
objectForKey:
是NSDictionary
方法。 NSDictionary
是类似于NSArray
的集合类,不同之处在于它使用键来区分项目,而不是使用索引。密钥是您提供的任意字符串。没有两个对象可以具有相同的键(就像NSArray
中的两个对象都不能具有相同的索引一样)。 valueForKey:
是一种KVC方法。它适用于ANY类。 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看起来并没有那么有用。实际上,它看起来很“罗word”。但是,当您想在运行时进行更改时,您可以做很多很酷的事情,而这些事情在其他语言中要困难得多(但这超出了您的问题范围)。
如果您想学习有关KVC的更多信息,如果您有Google的话,会有很多教程,特别是在Scott Stevenson的博客上。您还可以查看《 NSKeyValueCoding协议参考》。
希望有所帮助。
#2 楼
当执行valueForKey:
时,您需要给它一个NSString,而objectForKey:
可以将任何NSObject子类作为键。这是因为对于键-值编码,键始终是字符串。实际上,文档指出,即使为
valueForKey:
提供了NSString,它仍然会调用objectForKey:
,除非字符串以@
开头,在这种情况下,它将调用[super valueForKey:]
,后者可能会调用valueForUndefinedKey:
,这可能会引发异常。评论
您能给我您想要的文档链接吗?谢谢。
–阿里·阿敏(Ali Amin)
2014年1月23日18:24
@عليامين:就在这里
–dreamlax
2014年1月23日在22:09
#3 楼
这是一个尽可能使用objectForKey:
而不是valueForKey:
的重要原因-带有未知密钥的valueForKey:
会抛出NSUnknownKeyException
,说“此类不是针对密钥进行编码的键值”。评论
很高兴知道“ valueForKey:具有未知密钥会抛出NSUnknownKeyException,说”该类不是与密钥兼容的密钥值”
–onmyway133
2014年8月15日在8:52
对于NSDictionary来说,这根本不是真的,欢迎您尝试以下方法:NSLog(@“ Z:%@”,[@ {@“ X”:@(10),@“ Y”:@(20)} valueForKey:@“ Z”]); valueForKey将在不支持指定键的其他类上发出此类异常-但是对于NSDictionary子类-您只会收到一个安静的nil。尝试这个:
– Motti Shneor
19年7月4日在7:06
#4 楼
如上所述,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
中的值。 #5 楼
我将在这里尝试提供全面的答案。许多要点都出现在其他答案中,但是我发现每个答案都不完整,有些不正确。首先,
objectForKey:
是NSDictionary
方法,而valueForKey:
是任何KVC投诉类别(包括NSDictionary)都需要的KVC协议方法。 此外,正如@dreamlax所写,文档暗示
NSDictionary
使用其valueForKey:
实现来实现其objectForKey:
方法。换句话说-[NSDictionary valueForKey:]
调用[NSDictionary objectForKey:]
。这意味着,
valueForKey:
永远不会比objectForKey:
快(在相同的输入键上),尽管经过全面的测试,我发现相差约5%至15% ,超过数十亿的随机访问大量NSDictionary。在正常情况下-差异可以忽略不计。下一个:KVC协议仅适用于
NSString *
密钥,因此valueForKey:
将仅接受NSString *
(或子类)作为密钥,而NSDictionary
可以与其他对象一起使用作为密钥-objectForKey:
的“较低级别”接受任何可复制(兼容NSCopying协议)的对象作为密钥。不会为找不到的键发出NSDictionary's
-除非这是一个“特殊”键-以'@'开头的键-通常表示“聚合”功能键(例如valueForKey:
)。相反,当在NSDictionary中找不到密钥时,它将仅返回nil-与NSUnknownKeyException
相同。下面是一些测试代码来演示和证明我的笔记。- (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);
}
评论
对于NSDictionary对象,valueForKey的行为有所不同,具体取决于键是否以@符号开头。
–dreamlax
09年6月30日在10:17
objectForKey:接受任何对象作为键,而不仅仅是字符串。唯一的要求是密钥必须支持NSCopying协议。
–阿什利·克拉克(Ashley Clark)
2009年6月30日14:57
我很惊讶没有人通过指出valueForKey来纠正这个答案:从技术上讲,您不能访问相应的实例变量,而是(可以)管理实例变量的访问器方法。
–丹尼·乔玛(Dany Joumaa)
2012-10-25 3:49
警告:valueForKey可能会非常慢-它目前是我iPad应用程序中的主要瓶颈,它是如此之慢以至于用“标准”词典替换它会使应用程序明显加快。 iOS上的KVC出了点问题,我再也不会使用它了-不值得降低性能,而且无论如何都必须对其进行长时间的重新编写。这是在CALayers上使用带有NSString值的NSString键。仪器显示“ CAObject_valueForKey”占总运行时间的25%(!)
–亚当
13年1月4日在2:30
@Adam听起来很吓人。自iOS7起,您是否再次尝试过?如果是这样,此后情况是否有所改变?
– Unheilig
2014年3月14日在0:19