objectForKey和valueForKey之间的区别?

时间:2009-06-30 07:14:35

标签: objective-c cocoa key-value-coding

objectForKeyvalueForKey之间有什么区别? 我在文档中查看了它们,它们对我来说似乎是一样的。

6 个答案:

答案 0 :(得分:400)

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的更多信息,如果您特别针对Google Scott Stevenson's blog,那么有许多教程。您还可以查看NSKeyValueCoding Protocol Reference

希望有所帮助。

答案 1 :(得分:63)

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

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

答案 2 :(得分:21)

使用objectForKey:代替valueForKey: - valueForKey:并使用未知密钥的一个很好的理由会抛出NSUnknownKeyException说“此类不是关键值编码 - 符合密钥“。

答案 3 :(得分:12)

如上所述,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中的值将由同一类型的对象访问。

答案 4 :(得分:0)

我将在此处尝试提供全面的答案。许多要点都出现在其他答案中,但是我发现每个答案都不完整,有些不正确。

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

此外,正如@dreamlax所写,文档暗示NSDictionary实现其valueForKey:方法 USING objectForKey:实现。换句话说-[NSDictionary valueForKey:]呼叫[NSDictionary objectForKey:]

这意味着valueForKey:永远不会比objectForKey:快(在相同的输入键上),尽管我所做的全面测试隐含了大约5%到15%的差异,数十亿次的随机访问给一个庞大的NSDictionary。在正常情况下-差异可以忽略不计。

下一步:KVC协议仅适用于NSString *键,因此valueForKey:仅接受NSString *(或子类)作为键,而NSDictionary可以与其他类型一起使用对象作为键-以便“下级” objectForKey:接受任何可复制(符合NSCopying协议的对象)作为键。

最后NSDictionary'svalueForKey:的实现方式偏离了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);
}

答案 5 :(得分:0)

此表代表 objectForKeyvalueForKey 之间的四个差异。

//   |---------------------|-------------------------|------------------------|
//   |                     |      `objectForKey`     |      `valueForKey`     |
//   |---------------------|-------------------------|------------------------|
//   | Works on ...        |       NSDictionary      |   NSDictionary / KVC   |
//   |---------------------|-------------------------|------------------------|
//   | Throws exception    |            No           |       Yes (on KVC)     |
//   |---------------------|-------------------------|------------------------|
//   | Feed                |   NSObject's subclass   |        NSString        |
//   |---------------------|-------------------------|------------------------|
//   | Usage on KVC        |          cannot         |           can          |
//   |---------------------|-------------------------|------------------------|