Respostas:
objectForKey:
é um NSDictionary
método An NSDictionary
é uma classe de coleção semelhante a uma NSArray
, exceto que, em vez de usar índices, usa chaves para diferenciar itens. Uma chave é uma sequência arbitrária que você fornece. Dois objetos não podem ter a mesma chave (assim como dois objetos em um NSArray
podem ter o mesmo índice).
valueForKey:
é um método KVC. Funciona com QUALQUER classe. valueForKey:
permite acessar uma propriedade usando uma string para seu nome. Por exemplo, se eu tiver uma Account
classe com uma propriedade accountNumber
, posso fazer o seguinte:
NSNumber *anAccountNumber = [NSNumber numberWithInt:12345];
Account *newAccount = [[Account alloc] init];
[newAccount setAccountNumber:anAccountNUmber];
NSNumber *anotherAccountNumber = [newAccount accountNumber];
Usando o KVC, eu posso acessar a propriedade dinamicamente:
NSNumber *anAccountNumber = [NSNumber numberWithInt:12345];
Account *newAccount = [[Account alloc] init];
[newAccount setValue:anAccountNumber forKey:@"accountNumber"];
NSNumber *anotherAccountNumber = [newAccount valueForKey:@"accountNumber"];
Esses são conjuntos equivalentes de instruções.
Eu sei que você está pensando: uau, mas sarcasticamente. KVC não parece tão útil. De fato, parece "prolixo". Mas quando você deseja alterar as coisas em tempo de execução, pode fazer muitas coisas legais que são muito mais difíceis em outros idiomas (mas isso está além do escopo da sua pergunta).
Se você quiser saber mais sobre o KVC, existem muitos tutoriais se você pesquisar no Google, especialmente no blog de Scott Stevenson . Você também pode verificar a referência de protocolo NSKeyValueCoding .
Espero que ajude.
Quando você valueForKey:
precisa atribuir um NSString, ele objectForKey:
pode usar qualquer subclasse NSObject como chave. Isso ocorre porque para a codificação de valor-chave, as chaves são sempre cadeias de caracteres.
De fato, a documentação afirma que, mesmo quando você fornece valueForKey:
um NSString, ele será invocado de objectForKey:
qualquer maneira, a menos que a cadeia inicie com um @
, nesse caso, invoca [super valueForKey:]
, que pode chamar, o valueForUndefinedKey:
que pode gerar uma exceção.
Aqui está um ótimo motivo para usar objectForKey:
sempre que possível, em vez de valueForKey:
- valueForKey:
com uma chave desconhecida, NSUnknownKeyException
dizendo "esta classe não é compatível com a codificação do valor da chave".
Como dito, o objectForKey:
tipo de dados é :(id)aKey
o valueForKey:
tipo de dados :(NSString *)key
.
Por exemplo:
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.
Portanto, valueForKey:
levará apenas um valor de sequência e é um método KVC, enquanto objectForKey:
levará qualquer tipo de objeto.
O valor em objectForKey
será acessado pelo mesmo tipo de objeto.
Vou tentar fornecer uma resposta abrangente aqui. Muitos dos pontos aparecem em outras respostas, mas achei cada resposta incompleta e algumas incorretas.
Em primeiro lugar, objectForKey:
é um NSDictionary
método, enquanto valueForKey:
é um método de protocolo KVC exigido para qualquer classe de reclamação KVC - incluindo o NSDictionary.
Além disso, como o @dreamlax escreveu, a documentação sugere que NSDictionary
implementa seu valueForKey:
método USANDO sua objectForKey:
implementação. Em outras palavras - [NSDictionary valueForKey:]
chama [NSDictionary objectForKey:]
.
Isso implica que isso valueForKey:
nunca pode ser mais rápido do que objectForKey:
(na mesma chave de entrada), embora testes completos que eu tenha feito impliquem cerca de 5% a 15% de diferença, em bilhões de acesso aleatório a um enorme NSDictionary. Em situações normais - a diferença é insignificante.
Próximo: O protocolo KVC funciona apenas com NSString *
chaves, portanto valueForKey:
, aceita apenas uma NSString *
(ou subclasse) como chave, enquanto NSDictionary
pode trabalhar com outros tipos de objetos como chaves - para que o "nível mais baixo" objectForKey:
aceite qualquer objeto com capacidade de cópia (compatível com o protocolo NSCopying) como chave.
Por fim, a NSDictionary's
implementação de valueForKey:
desvios do comportamento padrão definido na documentação da KVC e NÃO emitirá um NSUnknownKeyException
para uma chave que não pode encontrar - a menos que seja uma chave "especial" - que comece com '@' - que geralmente significa um " agregação "tecla de função (por exemplo @"@sum, @"@avg"
). Em vez disso, ele simplesmente retornará um valor nulo quando uma chave não for encontrada no NSDictionary - comportando-se da mesma forma queobjectForKey:
A seguir, alguns códigos de teste para demonstrar e provar minhas anotações.
- (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);
}