objectForKeyvalueForKey有什么区别?
我在文档中都对它们进行了查找,对我来说它们似乎相同。

#1 楼

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

valueForKey:是一种KVC方法。它适用于ANY类。 valueForKey:允许您使用字符串作为属性来访问属性。因此,例如,如果我有一个带有属性AccountaccountNumber类,则可以执行以下操作:

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协议参考》。

希望有所帮助。

评论


对于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

#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);
}