objective-c objectForKey 和 valueForKey 之间的区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1062183/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Difference between objectForKey and valueForKey?
提问by Devoted
What is the difference between objectForKeyand valueForKey?
I looked both up in the documentation and they seemed the same to me.
objectForKey和 和有valueForKey什么区别?我在文档中查找了两者,它们对我来说似乎相同。
回答by Corey Floyd
objectForKey:is an NSDictionarymethod. An NSDictionaryis a collection class similar to an NSArray, except instead of using indexes, it uses keys to differentiate between items. A key is an arbitrary string you provide. No two objects can have the same key (just as no two objects in an NSArraycan have the same index).
objectForKey:是一种NSDictionary方法。AnNSDictionary是一个类似于 an 的集合类NSArray,不同之处在于它不使用索引,而是使用键来区分项目。键是您提供的任意字符串。没有两个对象可以有相同的键(就像一个中没有两个对象NSArray可以有相同的索引)。
valueForKey:is a KVC method. It works with ANY class. valueForKey:allows you to access a property using a string for its name. So for instance, if I have an Accountclass with a property accountNumber, I can do the following:
valueForKey:是一种 KVC 方法。它适用于任何类。valueForKey:允许您使用字符串作为名称来访问属性。例如,如果我有一个Account带有属性的类accountNumber,我可以执行以下操作:
NSNumber *anAccountNumber = [NSNumber numberWithInt:12345];
Account *newAccount = [[Account alloc] init];
[newAccount setAccountNumber:anAccountNUmber];
NSNumber *anotherAccountNumber = [newAccount accountNumber];
Using KVC, I can access the property dynamically:
使用 KVC,我可以动态访问该属性:
NSNumber *anAccountNumber = [NSNumber numberWithInt:12345];
Account *newAccount = [[Account alloc] init];
[newAccount setValue:anAccountNumber forKey:@"accountNumber"];
NSNumber *anotherAccountNumber = [newAccount valueForKey:@"accountNumber"];
Those are equivalent sets of statements.
这些是等效的语句集。
I know you're thinking: wow, but sarcastically. KVC doesn't look all that useful. In fact, it looks "wordy". But when you want to change things at runtime, you can do lots of cool things that are much more difficult in other languages (but this is beyond the scope of your question).
我知道你在想:哇,但讽刺的是。KVC 看起来不是那么有用。事实上,它看起来很“罗嗦”。但是当你想在运行时改变东西时,你可以做很多很酷的事情,这些事情在其他语言中要困难得多(但这超出了你的问题范围)。
If you want to learn more about KVC, there are many tutorials if you Google especially at Scott Stevenson's blog. You can also check out the NSKeyValueCoding Protocol Reference.
如果你想了解更多关于 KVC 的知识,谷歌有很多教程,尤其是Scott Stevenson 的博客。您还可以查看NSKeyValueCoding 协议参考。
Hope that helps.
希望有帮助。
回答by dreamlax
When you do valueForKey:you need to give it an NSString, whereas objectForKey:can take any NSObject subclass as a key. This is because for Key-Value Coding, the keys are always strings.
当你这样做时,valueForKey:你需要给它一个 NSString,而objectForKey:可以将任何 NSObject 子类作为键。这是因为对于键值编码,键总是字符串。
In fact, the documentation states that even when you give valueForKey:an NSString, it will invoke objectForKey:anyway unless the string starts with an @, in which case it invokes [super valueForKey:], which may call valueForUndefinedKey:which may raise an exception.
事实上,文档指出,即使您给出valueForKey:NSString,它也会调用objectForKey:,除非字符串以 an 开头@,在这种情况下,它调用[super valueForKey:]可能valueForUndefinedKey:会引发异常的调用。
回答by Nick Locking
Here's a great reason to use objectForKey:wherever possible instead of valueForKey:- valueForKey:with an unknown key will throw NSUnknownKeyExceptionsaying "this class is not key value coding-compliant for the key ".
这是objectForKey:尽可能使用而不是使用的一个很好的理由valueForKey:-valueForKey:使用未知键会抛出NSUnknownKeyException“此类不符合键值编码的键”。
回答by Harjot Singh
As said, the objectForKey:datatype is :(id)aKeywhereas the valueForKey:datatype is :(NSString *)key.
如前所述,objectForKey:数据类型是,:(id)aKey而valueForKey:数据类型是:(NSString *)key.
For example:
例如:
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.
So, valueForKey:will take only a string value and is a KVC method, whereas objectForKey:will take any type of object.
因此,valueForKey:将仅采用字符串值并且是 KVC 方法,而objectForKey:将采用任何类型的对象。
The value in objectForKeywill be accessed by the same kind of object.
in 的值objectForKey将被相同类型的对象访问。
回答by Motti Shneor
I'll try to provide a comprehensive answer here. Much of the points appear in other answers, but I found each answer incomplete, and some incorrect.
我会在这里尝试提供一个全面的答案。许多观点出现在其他答案中,但我发现每个答案都不完整,有些是不正确的。
First and foremost, objectForKey:is an NSDictionarymethod, while valueForKey:is a KVC protocol method required of any KVC complaint class - including NSDictionary.
首先,objectForKey:是一种NSDictionary方法,valueForKey:而是任何 KVC 投诉类(包括 NSDictionary)所需的 KVC 协议方法。
Furthermore, as @dreamlax wrote, documentation hints that NSDictionaryimplements its valueForKey:method USINGits objectForKey:implementation. In other words - [NSDictionary valueForKey:]calls on [NSDictionary objectForKey:].
此外,正如@dreamlax 所写,文档提示使用其实现来NSDictionary实现其valueForKey:方法。换句话说 -调用.objectForKey:[NSDictionary valueForKey:][NSDictionary objectForKey:]
This implies, that valueForKey:can never be faster than objectForKey:(on the same input key) although thorough testing I've done imply about 5% to 15% difference, over billions of random access to a huge NSDictionary. In normal situations - the difference is negligible.
这意味着,这valueForKey:永远不会比objectForKey:(在相同的输入键上)更快,尽管我所做的彻底测试意味着大约 5% 到 15% 的差异,超过数十亿次随机访问巨大的 NSDictionary。在正常情况下 - 差异可以忽略不计。
Next: KVC protocol only works with NSString *keys, hence valueForKey:will only accept an NSString *(or subclass) as key, whilst NSDictionarycan work with other kinds of objects as keys - so that the "lower level" objectForKey:accepts any copy-able (NSCopying protocol compliant) object as key.
下一个:KVC 协议仅适用于NSString *密钥,因此valueForKey:只接受一个NSString *(或子类)作为密钥,同时NSDictionary可以使用其他类型的对象作为密钥 - 以便“较低级别”objectForKey:接受任何可复制的(符合 NSCopying 协议的)对象作为关键。
Last, NSDictionary'simplementation of valueForKey:deviates from the standard behavior defined in KVC's documentation, and will NOT emit a NSUnknownKeyExceptionfor a key it can't find - unless this is a "special" key - one that begins with '@' - which usually means an "aggregation" function key (e.g. @"@sum, @"@avg"). Instead, it will simply return a nil when a key is not found in the NSDictionary - behaving the same as objectForKey:
最后,NSDictionary's实现valueForKey:偏离了 KVC 文档中定义的标准行为,并且不会NSUnknownKeyException为它找不到的键发出 a - 除非这是一个“特殊”键 - 以“@”开头的键 - 这通常意味着“聚合”功能键(例如@"@sum, @"@avg")。相反,当在 NSDictionary 中找不到键时,它只会返回一个 nil - 行为与objectForKey:
Following is some test code to demonstrate and prove my notes.
下面是一些测试代码来演示和证明我的笔记。
- (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);
}

