wake-up-neo.com

Unterschied zwischen objectForKey und valueForKey?

Was ist der Unterschied zwischen objectForKey und valueForKey? Ich habe beide in der Dokumentation nachgeschlagen und sie schienen mir gleich zu sein.

342
Devoted

objectForKey: Ist eine NSDictionary Methode. Eine NSDictionary ist eine Auflistungsklasse, die einer NSArray ähnelt. Statt Indizes zu verwenden, werden jedoch Schlüssel zur Unterscheidung zwischen Elementen verwendet. Ein Schlüssel ist eine beliebige Zeichenfolge, die Sie bereitstellen. Keine zwei Objekte können den gleichen Schlüssel haben (genau wie keine zwei Objekte in einem NSArray den gleichen Index haben können).

valueForKey: Ist eine KVC-Methode. Es funktioniert mit jeder Klasse. Mit valueForKey: Können Sie auf eine Eigenschaft zugreifen, indem Sie einen String als Namen verwenden. Wenn ich zum Beispiel eine Account -Klasse mit einer Eigenschaft accountNumber habe, 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"];

Das sind äquivalente Mengen von Aussagen.

Ich weiß, Sie denken: Wow, aber sarkastisch. KVC sieht nicht so nützlich aus. Tatsächlich sieht es "wortreich" aus. Aber wenn Sie Dinge zur Laufzeit ändern möchten, können Sie viele coole Dinge tun, die in anderen Sprachen viel schwieriger sind (aber das geht über den Rahmen Ihrer Frage hinaus).

Wenn Sie mehr über KVC erfahren möchten, gibt es viele Tutorials, die Sie bei Google speziell unter Scott Stevensons Blog . Sie können auch die NSKeyValueCoding Protocol Reference .

Ich hoffe, das hilft.

401
Corey Floyd

Wenn Sie valueForKey: ausführen, müssen Sie ihm einen NSString zuweisen, während objectForKey: eine beliebige NSObject-Unterklasse als Schlüssel verwenden kann. Dies liegt daran, dass die Schlüssel für die Schlüsselwertcodierung immer Zeichenfolgen sind.

In der Tat heißt es in der Dokumentation, dass selbst wenn Sie valueForKey: einen NSString übergeben, objectForKey: trotzdem aufgerufen wird, es sei denn, die Zeichenfolge beginnt mit einem @ ruft [super valueForKey:] auf, was valueForUndefinedKey: aufrufen kann, was eine Ausnahme auslösen kann.

64
dreamlax

Hier ist ein guter Grund, objectForKey: wo immer möglich statt valueForKey: - valueForKey: mit einem unbekannten Schlüssel wirft NSUnknownKeyException mit der Meldung "Diese Klasse ist für den Schlüssel nicht schlüsselwertkodierungskonform".

20
Nick Locking

Wie gesagt, der Datentyp objectForKey: Ist :(id)aKey, während der Datentyp valueForKey::(NSString *)key ist.

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. 

Daher nimmt valueForKey: Nur einen String-Wert an und ist eine KVC-Methode, wohingegen objectForKey: Jeden Objekttyp annimmt.

Auf den Wert in objectForKey wird von derselben Art von Objekt zugegriffen.

13
Harjot Singh

Ich werde versuchen, hier eine umfassende Antwort zu geben. Viele der Punkte tauchen in anderen Antworten auf, aber ich fand jede Antwort unvollständig und einige falsch.

In erster Linie ist objectForKey: Eine NSDictionary -Methode, während valueForKey: Eine KVC-Protokollmethode ist, die für jede KVC-Beschwerdeklasse erforderlich ist - einschließlich NSDictionary.

Wie @dreamlax schrieb, deutet die Dokumentation außerdem darauf hin, dass NSDictionary die Methode valueForKey: Implementiert MIT die Methode objectForKey: Implementierung. Mit anderen Worten - [NSDictionary valueForKey:] Ruft [NSDictionary objectForKey:] Auf.

Dies impliziert, dass valueForKey: Niemals schneller sein kann als objectForKey: (Auf derselben Eingabetaste), obwohl gründliche Tests, die ich durchgeführt habe, ungefähr 5% bis 15% Unterschied implizieren, über Milliarden von zufälligen Zugriffen auf ein riesiges NSDictionary. In normalen Situationen ist der Unterschied vernachlässigbar.

Weiter: Das KVC-Protokoll funktioniert nur mit NSString * - Schlüsseln, daher akzeptiert valueForKey: Nur einen NSString * (Oder eine Unterklasse) als Schlüssel, während NSDictionary mit anderen arbeiten kann Arten von Objekten als Schlüssel - so dass die "untere Ebene" objectForKey: jedes kopierfähige (NSCopying-Protokoll-konforme) Objekt als Schlüssel akzeptiert.

Zuletzt weicht die NSDictionary's - Implementierung von valueForKey: Vom Standardverhalten ab, das in der KVC-Dokumentation definiert ist, und gibt KEIN NSUnknownKeyException für einen Schlüssel aus, den es nicht finden kann - es sei denn, dies ist ein "special" -Taste - eine, die mit "@" beginnt - was normalerweise eine "Aggregation" -Funktionstaste bedeutet (z. B. @"@sum, @"@avg"). Stattdessen wird einfach eine Null zurückgegeben, wenn ein Schlüssel nicht im NSDictionary gefunden wird - verhält sich genauso wie objectForKey:

Das Folgende ist 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);
}
0
Motti Shneor