Respuestas:
objectForKey:
Es un NSDictionary
método. An NSDictionary
es una clase de colección similar a una NSArray
, excepto que en lugar de usar índices, usa claves para diferenciar entre elementos. Una clave es una cadena arbitraria que proporciona. No hay dos objetos que puedan tener la misma clave (de la misma manera que no hay dos objetos en un NSArray
puede tener el mismo índice).
valueForKey:
Es un método KVC. Funciona con CUALQUIER clase. valueForKey:
le permite acceder a una propiedad usando una cadena para su nombre. Entonces, por ejemplo, si tengo una Account
clase con una propiedad accountNumber
, puedo hacer lo siguiente:
NSNumber *anAccountNumber = [NSNumber numberWithInt:12345];
Account *newAccount = [[Account alloc] init];
[newAccount setAccountNumber:anAccountNUmber];
NSNumber *anotherAccountNumber = [newAccount accountNumber];
Usando KVC, puedo acceder a la propiedad dinámicamente:
NSNumber *anAccountNumber = [NSNumber numberWithInt:12345];
Account *newAccount = [[Account alloc] init];
[newAccount setValue:anAccountNumber forKey:@"accountNumber"];
NSNumber *anotherAccountNumber = [newAccount valueForKey:@"accountNumber"];
Esos son conjuntos equivalentes de declaraciones.
Sé que estás pensando: wow, pero con sarcasmo. KVC no parece tan útil. De hecho, se ve "prolijo". Pero cuando desea cambiar las cosas en tiempo de ejecución, puede hacer muchas cosas interesantes que son mucho más difíciles en otros idiomas (pero esto está fuera del alcance de su pregunta).
Si quieres aprender más sobre KVC, hay muchos tutoriales si buscas en Google especialmente en el blog de Scott Stevenson . También puede consultar la Referencia del protocolo NSKeyValueCoding .
Espero que ayude.
Cuando lo haga valueForKey:
, debe darle un NSString, mientras que objectForKey:
puede tomar cualquier subclase de NSObject como clave. Esto se debe a que para la codificación clave-valor, las claves siempre son cadenas.
De hecho, la documentación indica que, incluso cuando le da valueForKey:
un NSString, invocará de objectForKey:
todos modos a menos que la cadena comience con un @
, en cuyo caso invoca [super valueForKey:]
, lo que puede llamar, lo valueForUndefinedKey:
que puede generar una excepción.
Aquí hay una gran razón para usar objectForKey:
siempre que sea posible en lugar de hacerlo valueForKey:
: valueForKey:
con una clave desconocida aparecerá NSUnknownKeyException
"esta clase no es compatible con la codificación del valor de clave para la clave".
Como se dijo, el objectForKey:
tipo de datos es :(id)aKey
mientras que el valueForKey:
tipo de datos es :(NSString *)key
.
Por ejemplo:
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.
Por lo tanto, valueForKey:
tomará solo un valor de cadena y es un método KVC, mientras objectForKey:
que tomará cualquier tipo de objeto.
Se objectForKey
accederá al valor en el mismo tipo de objeto.
Trataré de proporcionar una respuesta integral aquí. Gran parte de los puntos aparecen en otras respuestas, pero encontré cada respuesta incompleta y algunas incorrectas.
En primer lugar, objectForKey:
es un NSDictionary
método, mientras que valueForKey:
es un método de protocolo KVC requerido de cualquier clase de queja KVC, incluido NSDictionary.
Además, como escribió @dreamlax, la documentación sugiere que NSDictionary
implementa su valueForKey:
método USANDO su objectForKey:
implementación. En otras palabras, [NSDictionary valueForKey:]
llama [NSDictionary objectForKey:]
.
Esto implica que valueForKey:
eso nunca puede ser más rápido que objectForKey:
(en la misma tecla de entrada) aunque las pruebas exhaustivas que he realizado implican una diferencia de aproximadamente 5% a 15%, sobre miles de millones de acceso aleatorio a un enorme NSDictionary. En situaciones normales, la diferencia es insignificante.
A continuación: el protocolo KVC solo funciona con NSString *
claves, por valueForKey:
lo tanto , solo aceptará una NSString *
(o subclase) como clave, mientras que NSDictionary
puede trabajar con otros tipos de objetos como claves, de modo que el "nivel inferior" objectForKey:
acepte cualquier objeto copiable (compatible con el protocolo NSCopying) como clave
Por último, la NSDictionary's
implementación de se valueForKey:
desvía del comportamiento estándar definido en la documentación de KVC y NO emitirá una NSUnknownKeyException
clave que no puede encontrar, a menos que sea una clave "especial", una que comienza con '@', que generalmente significa " agregación "tecla de función (por ejemplo @"@sum, @"@avg"
). En cambio, simplemente devolverá un valor nulo cuando no se encuentre una clave en NSDictionary, comportándose igual queobjectForKey:
Lo siguiente es un código de prueba para demostrar y probar mis notas.
- (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);
}