web-dev-qa-db-fra.com

Différence entre objectForKey et valueForKey?

Quelle est la différence entre objectForKey et valueForKey? J'ai regardé les deux dans la documentation et ils m'ont semblé identiques.

342
Devoted

objectForKey: est une méthode NSDictionary. Un NSDictionary est une classe de collection semblable à un NSArray, sauf qu'au lieu d'utiliser des index, il utilise des clés pour différencier les éléments. Une clé est une chaîne arbitraire que vous fournissez. Aucun objet ne peut avoir la même clé (tout comme aucun objet dans un NSArray ne peut avoir le même index).

valueForKey: est une méthode KVC. Cela fonctionne avec N'IMPORTE QUELLE classe. valueForKey: vous permet d'accéder à une propriété en utilisant une chaîne pour son nom. Ainsi, par exemple, si j'ai une classe Account avec une propriété accountNumber, je peux effectuer les opérations suivantes:

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

[newAccount setAccountNumber:anAccountNUmber];

NSNumber *anotherAccountNumber = [newAccount accountNumber];

En utilisant KVC, je peux accéder à la propriété de manière dynamique:

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

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

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

Ce sont des ensembles de déclarations équivalentes.

Je sais que vous pensez: wow, mais sarcastique. KVC ne semble pas très utile. En fait, il semble "verbeux". Toutefois, lorsque vous souhaitez modifier des éléments au moment de l'exécution, vous pouvez effectuer un grand nombre d'activités intéressantes, bien plus difficiles dans d'autres langues (mais cela dépasse le cadre de votre question).

Si vous voulez en savoir plus sur KVC, il existe de nombreux tutoriels si vous utilisez Google en particulier sur blog de Scott Stevenson . Vous pouvez également consulter NSKeyValueCoding Protocol Reference .

J'espère que ça t'as aidé.

401
Corey Floyd

Quand vous faites valueForKey: vous devez lui donner une chaîne NSString, alors que objectForKey: peut prendre n'importe quelle sous-classe NSObject comme clé. En effet, pour le codage clé-valeur, les clés sont toujours des chaînes.

En fait, la documentation indique que même lorsque vous donnez une chaîne NSString à valueForKey:, elle invoque objectForKey: de toute façon, à moins que la chaîne ne commence par un @, auquel cas il invoque [super valueForKey:]. , qui peut appeler valueForUndefinedKey: qui peut déclencher une exception.

64
dreamlax

Voici une bonne raison d’utiliser objectForKey: autant que possible au lieu de valueForKey: - valueForKey: avec une clé inconnue jettera NSUnknownKeyException en disant "cette classe n’est pas conforme au codage des valeurs de clé pour clé ".

20
Nick Locking

Comme dit, le type de données objectForKey: est :(id)aKey alors que le type de données valueForKey: est :(NSString *)key.

Par exemple:

 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. 

Donc, valueForKey: prendra uniquement une valeur de chaîne et est une méthode KVC, alors que objectForKey: prendra n'importe quel type d'objet.

La valeur dans objectForKey sera accessible par le même type d'objet.

13
Harjot Singh

Je vais essayer de fournir une réponse complète ici. La plupart des points apparaissent dans d'autres réponses, mais j'ai trouvé chaque réponse incomplète et parfois incorrecte.

Tout d’abord, objectForKey: est une méthode NSDictionary, tandis que valueForKey: est une méthode de protocole KVC requise pour toute classe de réclamation KVC, y compris NSDictionary.

En outre, comme @dreamlax l'a écrit, la documentation indique que NSDictionary implémente sa méthode valueForKey:UTILISANT son objectForKey:. En d'autres termes - [NSDictionary valueForKey:] appelle [NSDictionary objectForKey:].

Cela implique que valueForKey: ne peut jamais être plus rapide que objectForKey: (sur la même clé d'entrée), bien que des tests approfondis aient conduit à une différence d'environ 5% à 15%, sur des milliards d'accès aléatoires à une énorme NSDictionary. Dans des situations normales, la différence est négligeable.

Suivant: Le protocole KVC fonctionne uniquement avec les touches NSString *. Par conséquent, valueForKey: accepte uniquement un NSString * (ou une sous-classe) comme clé, tandis que NSDictionary peut fonctionner avec d'autres types d'objets keys - pour que le "niveau inférieur" objectForKey: accepte tout objet pouvant être copié (conforme au protocole NSCopying) comme clé.

Enfin, NSDictionary's l'implémentation de valueForKey: dévie du comportement standard défini dans la documentation de KVC et n'émettra PAS de NSUnknownKeyException pour une clé introuvable, à moins qu'il s'agisse d'une "spéciale". key - celle qui commence par '@' - qui signifie généralement une touche de fonction "agrégation" (par exemple, @"@sum, @"@avg"). Au lieu de cela, il retournera simplement un nil lorsqu'une clé n'est pas trouvée dans le NSDictionary - en se comportant de la même manière que objectForKey:

Voici un code de test pour démontrer et prouver mes 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);
}
0
Motti Shneor