Câu trả lời:
objectForKey:
là một NSDictionary
phương pháp. An NSDictionary
là một lớp tập hợp tương tự như một NSArray
, ngoại trừ thay vì sử dụng các chỉ mục, nó sử dụng các khóa để phân biệt giữa các mục. Khóa là một chuỗi tùy ý bạn cung cấp. Không có hai đối tượng có thể có cùng khóa (giống như không có hai đối tượng trong mộtNSArray
có thể có cùng chỉ mục).
valueForKey:
là một phương pháp KVC. Nó hoạt động với bất kỳ lớp nào. valueForKey:
cho phép bạn truy cập một thuộc tính bằng cách sử dụng một chuỗi cho tên của nó. Vì vậy, ví dụ, nếu tôi có một Account
lớp với một thuộc tính accountNumber
, tôi có thể làm như sau:
NSNumber *anAccountNumber = [NSNumber numberWithInt:12345];
Account *newAccount = [[Account alloc] init];
[newAccount setAccountNumber:anAccountNUmber];
NSNumber *anotherAccountNumber = [newAccount accountNumber];
Sử dụng KVC, tôi có thể truy cập vào tài sản một cách linh hoạt:
NSNumber *anAccountNumber = [NSNumber numberWithInt:12345];
Account *newAccount = [[Account alloc] init];
[newAccount setValue:anAccountNumber forKey:@"accountNumber"];
NSNumber *anotherAccountNumber = [newAccount valueForKey:@"accountNumber"];
Đó là những bộ báo cáo tương đương.
Tôi biết bạn đang nghĩ: wow, nhưng mỉa mai. KVC không có vẻ hữu ích. Trong thực tế, nó trông "dài dòng". Nhưng khi bạn muốn thay đổi mọi thứ trong thời gian chạy, bạn có thể thực hiện nhiều điều thú vị khó khăn hơn nhiều trong các ngôn ngữ khác (nhưng điều này nằm ngoài phạm vi câu hỏi của bạn).
Nếu bạn muốn tìm hiểu thêm về KVC, có rất nhiều hướng dẫn nếu bạn Google đặc biệt là tại blog của Scott Stevenson . Bạn cũng có thể kiểm tra Tham chiếu Giao thức NSKeyValueCoding .
Mong rằng sẽ giúp.
Khi bạn valueForKey:
cần cung cấp cho nó một NSString, trong khi đó objectForKey:
có thể lấy bất kỳ lớp con NSObject nào làm khóa. Điều này là do mã hóa khóa-giá trị, các khóa luôn là các chuỗi.
Trong thực tế, tài liệu nói rằng ngay cả khi bạn cung cấp valueForKey:
NSString, nó sẽ gọi bằng objectForKey:
mọi cách trừ khi chuỗi bắt đầu bằng một @
, trong trường hợp nó gọi [super valueForKey:]
, có thể gọi valueForUndefinedKey:
có thể đưa ra ngoại lệ.
Đây là một lý do tuyệt vời để sử dụng objectForKey:
bất cứ nơi nào có thể thay vì valueForKey:
- valueForKey:
với một khóa không xác định sẽ NSUnknownKeyException
nói rằng "lớp này không phải là giá trị khóa tuân thủ mã hóa cho khóa".
Như đã nói, objectForKey:
kiểu dữ liệu :(id)aKey
trong khi valueForKey:
kiểu dữ liệu là:(NSString *)key
.
Ví dụ:
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.
Vì vậy, valueForKey:
sẽ chỉ lấy một giá trị chuỗi và là phương thức KVC, trong khi đóobjectForKey:
sẽ lấy bất kỳ loại đối tượng nào.
Giá trị trong objectForKey
sẽ được truy cập bởi cùng loại đối tượng.
Tôi sẽ cố gắng cung cấp một câu trả lời toàn diện ở đây. Phần lớn các điểm xuất hiện trong các câu trả lời khác, nhưng tôi thấy mỗi câu trả lời không đầy đủ, và một số điểm không chính xác.
Đầu tiên và quan trọng nhất, objectForKey:
là một NSDictionary
phương pháp, trong khivalueForKey:
là một phương thức giao thức KVC cần có của bất kỳ lớp khiếu nại KVC nào - bao gồm NSDipedia.
Hơn nữa, như @dreamlax đã viết, tài liệu gợi ý NSDictionary
thực hiện valueForKey:
phương pháp SỬ DỤNG việc objectForKey:
thực hiện nó . Nói cách khác - [NSDictionary valueForKey:]
gọi vào[NSDictionary objectForKey:]
.
Điều này ngụ ý, điều đó valueForKey:
không bao giờ có thể nhanh hơnobjectForKey:
(trên cùng một khóa đầu vào) mặc dù thử nghiệm kỹ lưỡng tôi đã thực hiện ngụ ý chênh lệch khoảng 5% đến 15%, qua hàng tỷ truy cập ngẫu nhiên vào một NSDipedia khổng lồ. Trong tình huống bình thường - sự khác biệt là không đáng kể.
Tiếp theo: Giao thức KVC chỉ hoạt động với NSString *
các khóa, do đó valueForKey:
sẽ chỉ chấp nhận một NSString *
(hoặc lớp con) làm khóa, trong khi NSDictionary
có thể hoạt động với các loại đối tượng khác làm khóa - để "mức thấp hơn" objectForKey:
chấp nhận mọi đối tượng có thể sao chép (tuân thủ giao thức NSCopying) làm chìa khóa
Cuối cùng, NSDictionary's
việc thực hiện các sai valueForKey:
lệch so với hành vi tiêu chuẩn được xác định trong tài liệu của KVC và sẽ KHÔNG phát ra NSUnknownKeyException
khóa mà nó không thể tìm thấy - trừ khi đây là khóa "đặc biệt" - bắt đầu bằng '@' - thường có nghĩa là " tập hợp "phím chức năng (ví dụ @"@sum, @"@avg"
). Thay vào đó, nó sẽ chỉ trả về một con số không khi không tìm thấy khóa trong NSDipedia - hoạt động giống nhưobjectForKey:
Sau đây là một số mã kiểm tra để chứng minh và chứng minh ghi chú của tôi.
- (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);
}