Risposte:
objectForKey:
è un NSDictionary
metodo. An NSDictionary
è una classe di raccolta simile a an NSArray
, tranne che invece di utilizzare gli indici, utilizza le chiavi per differenziare gli elementi. Una chiave è una stringa arbitraria che fornisci. Non ci sono due oggetti che possono avere la stessa chiave (così come non ci sono due oggetti in uno NSArray
può avere lo stesso indice).
valueForKey:
è un metodo KVC. Funziona con QUALSIASI classe. valueForKey:
ti permette di accedere a una proprietà usando una stringa per il suo nome. Ad esempio, se ho una Account
classe con una proprietà accountNumber
, posso fare quanto segue:
NSNumber *anAccountNumber = [NSNumber numberWithInt:12345];
Account *newAccount = [[Account alloc] init];
[newAccount setAccountNumber:anAccountNUmber];
NSNumber *anotherAccountNumber = [newAccount accountNumber];
Utilizzando KVC, posso accedere alla proprietà in modo dinamico:
NSNumber *anAccountNumber = [NSNumber numberWithInt:12345];
Account *newAccount = [[Account alloc] init];
[newAccount setValue:anAccountNumber forKey:@"accountNumber"];
NSNumber *anotherAccountNumber = [newAccount valueForKey:@"accountNumber"];
Quelle sono serie equivalenti di dichiarazioni.
So che stai pensando: wow, ma sarcasticamente. KVC non sembra molto utile. In effetti, sembra "prolisso". Ma quando vuoi cambiare le cose in fase di esecuzione, puoi fare molte cose interessanti che sono molto più difficili in altre lingue (ma questo va oltre lo scopo della tua domanda).
Se vuoi saperne di più su KVC, ci sono molti tutorial su Google, in particolare sul blog di Scott Stevenson . Puoi anche consultare il riferimento al protocollo NSKeyValueCoding .
Spero che aiuti.
Quando lo fai valueForKey:
devi dargli una NSString, mentre objectForKey:
può prendere qualsiasi sottoclasse NSObject come chiave. Questo perché per la codifica valore-chiave, le chiavi sono sempre stringhe.
In effetti, la documentazione afferma che anche quando si dà valueForKey:
un NSString, invocherà objectForKey:
comunque a meno che la stringa non inizi con un @
, nel qual caso invoca [super valueForKey:]
, che può chiamare valueForUndefinedKey:
che può sollevare un'eccezione.
Ecco un ottimo motivo per usarlo objectForKey:
laddove possibile anziché valueForKey:
- valueForKey:
con una chiave sconosciuta verrà NSUnknownKeyException
detto "questa classe non è conforme alla codifica del valore chiave per la chiave".
Come detto, il objectForKey:
tipo di dati è :(id)aKey
mentre il valueForKey:
tipo di dati è :(NSString *)key
.
Per esempio:
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.
Quindi, valueForKey:
prenderà solo un valore stringa ed è un metodo KVC, mentre objectForKey:
prenderà qualsiasi tipo di oggetto.
Il valore in objectForKey
sarà accessibile dallo stesso tipo di oggetto.
Proverò a fornire una risposta completa qui. Gran parte dei punti appaiono in altre risposte, ma ho trovato ciascuna risposta incompleta e alcune errate.
Innanzitutto, objectForKey:
è un NSDictionary
metodo, mentre valueForKey:
è richiesto un metodo di protocollo KVC per qualsiasi classe di reclamo KVC, incluso NSDictionary.
Inoltre, come ha scritto @dreamlax, la documentazione suggerisce che NSDictionary
implementa il suo valueForKey:
metodo USANDO la sua objectForKey:
implementazione. In altre parole: [NSDictionary valueForKey:]
chiama [NSDictionary objectForKey:]
.
Ciò implica che ciò valueForKey:
non potrà mai essere più veloce di objectForKey:
(sulla stessa chiave di input) anche se test approfonditi che ho fatto implicano una differenza dal 5% al 15% circa, oltre miliardi di accessi casuali a un enorme NSDictionary. In situazioni normali - la differenza è trascurabile.
Next: Il protocollo KVC funziona solo con le NSString *
chiavi, quindi valueForKey:
accetta solo una NSString *
(o sottoclasse) come chiave, mentre NSDictionary
può funzionare con altri tipi di oggetti come chiavi - in modo che il "livello inferiore" objectForKey:
accetti qualsiasi oggetto in grado di copiare (conforme al protocollo NSCopying) come chiave.
Infine, l' NSDictionary's
implementazione di valueForKey:
deviazioni dal comportamento standard definito nella documentazione di KVC e NON emetterà una NSUnknownKeyException
per una chiave che non riesce a trovare - a meno che questa non sia una chiave "speciale" - quella che inizia con "@" - che di solito significa un " tasto funzione "aggregazione" (ad es @"@sum, @"@avg"
.). Al contrario, restituirà semplicemente uno zero quando non viene trovata una chiave in NSDictionary - comportandosi allo stesso modo diobjectForKey:
Di seguito è riportato un codice di prova per dimostrare e dimostrare le mie note.
- (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);
}