Réponses:
objectForKey:
est une NSDictionary
méthode. An NSDictionary
est une classe de collection similaire à an 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. Deux objets ne peuvent pas 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 Account
classe avec une propriété accountNumber
, je peux faire ce qui suit:
NSNumber *anAccountNumber = [NSNumber numberWithInt:12345];
Account *newAccount = [[Account alloc] init];
[newAccount setAccountNumber:anAccountNUmber];
NSNumber *anotherAccountNumber = [newAccount accountNumber];
En utilisant KVC, je peux accéder dynamiquement à la propriété:
NSNumber *anAccountNumber = [NSNumber numberWithInt:12345];
Account *newAccount = [[Account alloc] init];
[newAccount setValue:anAccountNumber forKey:@"accountNumber"];
NSNumber *anotherAccountNumber = [newAccount valueForKey:@"accountNumber"];
Ce sont des ensembles d'instructions équivalents.
Je sais que tu penses: wow, mais sarcastique. KVC ne semble pas très utile. En fait, ça a l'air "verbeux". Mais lorsque vous voulez changer des choses au moment de l'exécution, vous pouvez faire beaucoup de choses sympas qui sont beaucoup plus difficiles dans d'autres langues (mais cela dépasse la portée de votre question).
Si vous voulez en savoir plus sur KVC, il existe de nombreux tutoriels si vous Google en particulier sur le blog de Scott Stevenson . Vous pouvez également consulter la référence du protocole NSKeyValueCoding .
J'espère que cela pourra aider.
Lorsque vous le faites, valueForKey:
vous devez lui donner une NSString, alors que vous objectForKey:
pouvez prendre n'importe quelle sous-classe NSObject comme clé. En effet, pour le codage valeur-clé, les clés sont toujours des chaînes.
En fait, la documentation indique que même lorsque vous donnez valueForKey:
une NSString, elle sera invoquée de objectForKey:
toute façon à moins que la chaîne ne commence par un @
, auquel cas elle invoque [super valueForKey:]
, qui peut appeler valueForUndefinedKey:
ce qui peut déclencher une exception.
Voici une excellente raison d'utiliser objectForKey:
autant que possible au lieu de valueForKey:
- valueForKey:
avec une clé inconnue, on NSUnknownKeyException
dira "cette classe n'est pas conforme au codage de la valeur de clé pour la clé".
Comme dit, le objectForKey:
type de données est :(id)aKey
alors que le valueForKey:
type de données l'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.
Ainsi, valueForKey:
ne prendra qu'une valeur de chaîne et est une méthode KVC, tandis que objectForKey:
prendra tout type d'objet.
La valeur de objectForKey
sera accessible par le même type d'objet.
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 certaines incorrectes.
Tout d'abord, objectForKey:
est une NSDictionary
méthode, tandis valueForKey:
qu'une méthode de protocole KVC est requise pour toute classe de plainte KVC - y compris NSDictionary.
En outre, comme l'a écrit @dreamlax, la documentation indique la NSDictionary
mise en œuvre de sa valueForKey:
méthode en utilisant son objectForKey:
implémentation. En d'autres termes - [NSDictionary valueForKey:]
appelle [NSDictionary objectForKey:]
.
Cela implique que valueForKey:
cela ne peut jamais être plus rapide que objectForKey:
(sur la même clé d'entrée), bien que des tests approfondis que j'ai effectués impliquent une différence d'environ 5% à 15%, sur des milliards d'accès aléatoire à un énorme NSDictionary. Dans des situations normales - la différence est négligeable.
Suivant: Le protocole KVC ne fonctionne qu'avec des NSString *
clés, donc valueForKey:
n'acceptera NSString *
qu'une clé (ou sous-classe) comme clé, tout en NSDictionary
pouvant fonctionner avec d'autres types d'objets comme clés - de sorte que le "niveau inférieur" objectForKey:
accepte tout objet copiable (compatible avec le protocole NSCopying) comme clé.
Enfin, l' NSDictionary's
implémentation de valueForKey:
s'écarte du comportement standard défini dans la documentation de KVC et n'émettra PAS NSUnknownKeyException
de clé qu'il ne trouve pas - sauf s'il s'agit d'une clé "spéciale" - qui commence par "@" - ce qui signifie généralement un " agrégation "touche de fonction (par exemple @"@sum, @"@avg"
). Au lieu de cela, il retournera simplement un zéro lorsqu'aucune clé ne sera trouvée dans le NSDictionary - se comportant de la même manière queobjectForKey:
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);
}