Was ist der Unterschied zwischen objectForKey
und valueForKey
? Ich habe beide in der Dokumentation nachgeschlagen und sie schienen mir gleich zu sein.
Was ist der Unterschied zwischen objectForKey
und valueForKey
? Ich habe beide in der Dokumentation nachgeschlagen und sie schienen mir gleich zu sein.
Antworten:
objectForKey:
ist eine NSDictionary
Methode. An NSDictionary
ist eine Auflistungsklasse ähnlich einer NSArray
, außer dass anstelle von Indizes Schlüssel zur Unterscheidung zwischen Elementen verwendet werden. Ein Schlüssel ist eine beliebige Zeichenfolge, die Sie angeben. Keine zwei Objekte können denselben Schlüssel haben (so wie keine zwei Objekte in einem NSArray
denselben Index haben können).
valueForKey:
ist eine KVC-Methode. Es funktioniert mit jeder Klasse. valueForKey:
Ermöglicht den Zugriff auf eine Eigenschaft mithilfe einer Zeichenfolge für ihren Namen. Wenn ich beispielsweise eine Account
Klasse mit einer Eigenschaft habe accountNumber
, kann ich Folgendes tun:
NSNumber *anAccountNumber = [NSNumber numberWithInt:12345];
Account *newAccount = [[Account alloc] init];
[newAccount setAccountNumber:anAccountNUmber];
NSNumber *anotherAccountNumber = [newAccount accountNumber];
Mit KVC kann ich dynamisch auf die Eigenschaft zugreifen:
NSNumber *anAccountNumber = [NSNumber numberWithInt:12345];
Account *newAccount = [[Account alloc] init];
[newAccount setValue:anAccountNumber forKey:@"accountNumber"];
NSNumber *anotherAccountNumber = [newAccount valueForKey:@"accountNumber"];
Dies sind äquivalente Sätze von Anweisungen.
Ich weiß, dass du denkst: Wow, aber sarkastisch. KVC sieht gar nicht so nützlich aus. In der Tat sieht es "wortreich" aus. Wenn Sie jedoch zur Laufzeit Änderungen vornehmen möchten, können Sie viele coole Dinge tun, die in anderen Sprachen viel schwieriger sind (dies geht jedoch über den Rahmen Ihrer Frage hinaus).
Wenn Sie mehr über KVC erfahren möchten, gibt es viele Tutorials, wenn Sie Google speziell in Scott Stevensons Blog verwenden . Sie können auch die NSKeyValueCoding-Protokollreferenz überprüfen .
Ich hoffe, das hilft.
Wenn Sie dies tun valueForKey:
, müssen Sie ihm einen NSString geben, während objectForKey:
jede NSObject-Unterklasse als Schlüssel verwendet werden kann. Dies liegt daran, dass bei der Schlüsselwertcodierung die Schlüssel immer Zeichenfolgen sind.
Tatsächlich heißt es in der Dokumentation, dass selbst wenn Sie valueForKey:
einen NSString angeben, dieser objectForKey:
trotzdem aufgerufen wird, es sei denn, die Zeichenfolge beginnt mit einem @
. In diesem Fall wird ein [super valueForKey:]
Aufruf aufgerufen, valueForUndefinedKey:
der möglicherweise eine Ausnahme auslöst .
Hier ist ein guter Grund, objectForKey:
wo immer möglich zu verwenden , anstatt valueForKey:
- valueForKey:
mit einem unbekannten Schlüssel wird die Meldung NSUnknownKeyException
"Diese Klasse ist nicht für die Schlüsselwertcodierung für den Schlüssel kompatibel" ausgegeben.
Wie gesagt, der objectForKey:
Datentyp ist, :(id)aKey
während der valueForKey:
Datentyp ist :(NSString *)key
.
Zum Beispiel:
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.
Nimmt also valueForKey:
nur einen Zeichenfolgenwert an und ist eine KVC-Methode, während objectForKey:
jede Art von Objekt verwendet wird.
Auf den Wert in objectForKey
wird von derselben Art von Objekt zugegriffen.
Ich werde versuchen, hier eine umfassende Antwort zu geben. Viele der Punkte erscheinen in anderen Antworten, aber ich fand jede Antwort unvollständig und einige falsch.
In erster Linie objectForKey:
handelt es sich um eine NSDictionary
Methode, während valueForKey:
für jede KVC-Beschwerdeklasse - einschließlich NSDictionary - eine KVC-Protokollmethode erforderlich ist.
Wie @dreamlax schrieb, gibt die Dokumentation außerdem Hinweise darauf, dass NSDictionary
die valueForKey:
Methode mithilfe ihrer objectForKey:
Implementierung implementiert wird. Mit anderen Worten - [NSDictionary valueForKey:]
ruft an [NSDictionary objectForKey:]
.
Dies impliziert, dass valueForKey:
dies niemals schneller sein kann als objectForKey:
(mit demselben Eingabeschlüssel), obwohl gründliche Tests, die ich durchgeführt habe, einen Unterschied von etwa 5% bis 15% gegenüber Milliarden von Direktzugriffen auf ein riesiges NSDictionary bedeuten. In normalen Situationen ist der Unterschied vernachlässigbar.
Weiter: Das KVC-Protokoll funktioniert nur mit NSString *
Schlüsseln und valueForKey:
akzeptiert daher nur eine NSString *
(oder Unterklasse) als Schlüssel, während NSDictionary
es mit anderen Arten von Objekten als Schlüssel arbeiten kann - so dass die "untere Ebene" objectForKey:
jedes kopierbare (NSCopying-Protokoll-kompatible) Objekt akzeptiert als Schlüssel.
Schließlich weicht die NSDictionary's
Implementierung valueForKey:
von dem in der KVC-Dokumentation definierten Standardverhalten ab und gibt KEINEN NSUnknownKeyException
für einen Schlüssel aus, den es nicht finden kann - es sei denn, dies ist ein "spezieller" Schlüssel - der mit '@' beginnt - was normalerweise ein "bedeutet. Aggregation "Funktionstaste (zB @"@sum, @"@avg"
). Stattdessen wird einfach eine Null zurückgegeben, wenn kein Schlüssel im NSDictionary gefunden wird - und verhält sich genauso wieobjectForKey:
Es folgt ein Testcode, um meine Notizen zu demonstrieren und zu beweisen.
- (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);
}