ความแตกต่างระหว่างobjectForKey
และvalueForKey
คืออะไร? ฉันค้นหาทั้งในเอกสารและพวกเขาก็ดูเหมือนฉัน
ความแตกต่างระหว่างobjectForKey
และvalueForKey
คืออะไร? ฉันค้นหาทั้งในเอกสารและพวกเขาก็ดูเหมือนฉัน
คำตอบ:
objectForKey:
เป็นNSDictionary
วิธีการ An NSDictionary
เป็นคลาสคอลเลกชันที่คล้ายกับNSArray
ยกเว้นแทนที่จะใช้ดัชนีจะใช้คีย์เพื่อแยกความแตกต่างระหว่างรายการ คีย์คือสตริงที่คุณกำหนดเอง ไม่มีวัตถุใดที่สามารถมีคีย์เดียวกันได้ (เช่นเดียวกับที่วัตถุสองอันในNSArray
ไม่สามารถมีดัชนีเดียวกันได้)
valueForKey:
เป็นวิธี KVC มันทำงานร่วมกับชั้นเรียนใด ๆ 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 มีบทเรียนหลายถ้าคุณ Google โดยเฉพาะอย่างยิ่งในบล็อกของสกอตต์ของสตีเวนสัน นอกจากนี้คุณยังสามารถตรวจสอบการอ้างอิงโปรโตคอล NSKeyValueCoding
หวังว่าจะช่วย
เมื่อคุณvalueForKey:
ต้องให้ NSString ในขณะที่objectForKey:
สามารถใช้คลาสย่อย NSObject เป็นคีย์ได้ นี่เป็นเพราะสำหรับการเข้ารหัสคีย์ - ค่าคีย์จะเป็นสตริงเสมอ
ในความเป็นจริงเอกสารระบุว่าแม้ว่าคุณจะให้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"
) แต่จะคืนค่าศูนย์เมื่อไม่พบรหัสในพจนานุกรม NSDictionaryobjectForKey:
ต่อไปนี้เป็นรหัสทดสอบเพื่อแสดงและพิสูจน์บันทึกของฉัน
- (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);
}