У чому різниця між objectForKey
і valueForKey
? Я переглянув обох документацію, і вони здалися мені однаковими.
У чому різниця між objectForKey
і valueForKey
? Я переглянув обох документацію, і вони здалися мені однаковими.
Відповіді:
objectForKey:
є NSDictionary
методом. NSDictionary
Клас колекції схожий на NSArray
, за винятком того, замість використання індексів, він використовує ключі , щоб розрізняти предмети. Ключ - це довільна рядок, який ви надаєте. Жоден два об'єкти не можуть мати один і той же ключ (так само, як жоден два об’єкти в банці не NSArray
може мати однаковий індекс).
valueForKey:
є методом КВК. Він працює з будь-яким класом. valueForKey:
дозволяє отримати доступ до ресурсу, використовуючи рядок для його імені. Наприклад, якщо у мене є Account
клас із властивістю accountNumber
, я можу зробити наступне:
NSNumber *anAccountNumber = [NSNumber numberWithInt:12345];
Account *newAccount = [[Account alloc] init];
[newAccount setAccountNumber:anAccountNUmber];
NSNumber *anotherAccountNumber = [newAccount accountNumber];
Використовуючи KVC, я можу отримати доступ до властивості динамічно:
NSNumber *anAccountNumber = [NSNumber numberWithInt:12345];
Account *newAccount = [[Account alloc] init];
[newAccount setValue:anAccountNumber forKey:@"accountNumber"];
NSNumber *anotherAccountNumber = [newAccount valueForKey:@"accountNumber"];
Це еквівалентні набори тверджень.
Я знаю, ти думаєш: вау, але саркастично. KVC не виглядає таким корисним. Насправді це виглядає «багатослівно». Але коли ви хочете змінити речі під час виконання, ви можете зробити багато цікавих речей, які набагато складніше в інших мовах (але це виходить за рамки вашого питання).
Якщо ви хочете дізнатися більше про KVC, то у вашому блозі Скотта Стівенсона є багато навчальних посібників . Ви також можете перевірити посилання на протокол NSKeyValueCoding .
Сподіваюся, що це допомагає.
Коли вам valueForKey:
потрібно надати йому NSString, тоді як objectForKey:
можна взяти будь-який підклас NSObject як ключ. Це тому, що для кодування Key-Value ключові слова - це завжди рядки.
Насправді в документації зазначено, що навіть коли ви даєте valueForKey:
NSString, він буде викликати objectForKey:
все одно, якщо рядок не починається з @
, у цьому випадку він викликає [super valueForKey:]
, що може викликати, valueForUndefinedKey:
що може викликати виняток.
Ось чудова причина використовувати, objectForKey:
де це можливо, а не valueForKey:
- valueForKey:
невідомим ключем буде NSUnknownKeyException
висловлюватися «цей клас не є ключовим значенням, що відповідає кодуванню ключа».
Як було сказано, objectForKey:
тип даних, :(id)aKey
тоді як valueForKey:
тип даних є :(NSString *)key
.
Наприклад:
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.
Отже, valueForKey:
візьме лише значення рядка і є методом KVC, тоді як objectForKey:
візьме будь-який тип об'єкта.
Доступ до значення в objectForKey
буде здійснюватися тим самим видом об’єкта.
Я спробую надати тут вичерпну відповідь. Значна частина пунктів відображається в інших відповідях, але я вважав, що кожна відповідь є неповною, а деякі - неправильною.
Перш за все, objectForKey:
це NSDictionary
метод, в той час valueForKey:
як метод протоколу KVC, необхідний для будь-якого класу скарг KVC - включаючи NSDictionary.
Крім того, як писав @dreamlax, документація натякає на те, що NSDictionary
реалізується його valueForKey:
метод, використовуючи його objectForKey:
реалізацію. Іншими словами - [NSDictionary valueForKey:]
дзвінки [NSDictionary objectForKey:]
.
Це означає, що valueForKey:
це ніколи не може бути швидшим, ніж objectForKey:
(на тій же клавіші введення), хоча ретельне тестування, яке я робив, передбачає різницю від 5% до 15%, за мільярди випадкового доступу до величезного NSDictionary. У нормальних ситуаціях - різниця незначна.
Далі: Протокол KVC працює лише з NSString *
ключами, отже, valueForKey:
він приймає лише NSString *
ключ (або підклас) як ключ, тоді як він NSDictionary
може працювати з іншими типами об'єктів як ключі - так що "нижчий рівень" objectForKey:
приймає будь-який об'єкт, здатний до копіювання (сумісний з протоколом NSCopying) як ключовий.
Нарешті, NSDictionary's
реалізація valueForKey:
відхиляється від стандартної поведінки, визначеної в документації KVC, і НЕ випромінює NSUnknownKeyException
ключ, який він не може знайти - якщо тільки це не "спеціальний" ключ - той, що починається з "@" - що зазвичай означає " агрегація "функціональна клавіша (наприклад @"@sum, @"@avg"
). Натомість, він просто поверне нуль, коли ключ не знайдений у NSDictionary - він поводиться так само, якobjectForKey:
Далі наведено кілька тестових кодів, щоб продемонструвати та довести мої замітки.
- (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);
}