จะตรวจสอบว่า NSDictionary หรือ NSMutableDictionary มีรหัสได้อย่างไร?


456

ฉันต้องตรวจสอบว่า dict มีรหัสหรือไม่ อย่างไร?


4
(สำหรับทุกคนที่ไปที่นี่โปรดทราบว่านี่เป็นคำถามที่เก่ามากคำตอบ SaintMacintosh ด้านล่างเป็นสถานะของศิลปะมันเป็นเวลาห้าปีข้างหน้าของ QA นี้หวังว่ามันจะช่วยได้)
Fattie

1
ที่จริงแล้วคำตอบของ Andy Dent ยังให้ความทันสมัยและบริบทมากขึ้น และมันทำสิ่งนี้เร็วกว่า SaintMacintosh ทำตัวเองชอบมากเลื่อนลงอีกหน่อย
Peter Kämpf

1
เขาใช้: keysByName [test]! = nil! = ไม่มีการตรวจสอบซ้ำซ้อนและ IMHO อ่านน้อยลง ฉันแค่ต้องการแชร์ TL; เวอร์ชั่น DR สำหรับคนที่กำลังดูไวยากรณ์
Andrew Hoos

ฉันเห็นด้วยกับ @SaintMacintosh คำตอบของเขาสั้นกระชับกว่านี้มาก
Steve Schwarcz

หากคุณต้องการที่จะตรวจสอบว่าNSDictionaryมีคีย์ใด ๆ (ไม่เฉพาะเจาะจง) คุณควรใช้[dictionary allKeys].count == 0ถ้าcountเป็นมีคีย์ในไม่มี0 NSDictionary
Aleksander Azizi

คำตอบ:


768

objectForKey จะคืนค่าศูนย์ถ้าไม่มีคีย์


29
และจะเกิดอะไรขึ้นถ้าคีย์มีอยู่ แต่ค่าที่สอดคล้องกันคือไม่มี?
Fyodor Soikin

232
มันเป็นไปไม่ได้. คุณไม่สามารถเพิ่มศูนย์ลงใน NSDictionary คุณจะต้องใช้[NSNull null]แทน
Ole Begemann

10
@fyodor an nsdictionay จะส่ง NSInvalidArgumentException หากคุณพยายามแทรกค่าศูนย์ดังนั้นไม่ควรมีกรณีที่มีคีย์อยู่ แต่ค่าที่เกี่ยวข้องคือศูนย์
แบรด The App Guy

3
คุณไม่ต้องการใช้ valueForKey เหมือนที่เรียกว่า objectForKey ถ้าจำเป็น?
Raffi Khatchadourian

6
คุณไม่เคยต้องการใช้ valueForKey สำหรับพจนานุกรม JSON เลย นั่นเป็นเพราะ JSON สามารถมีสตริงใด ๆเป็นกุญแจ ตัวอย่างเช่นหากมี "@count" เป็นคีย์ดังนั้น objectForKey: @ "@ count" จะให้ค่าที่ถูกต้อง แต่ valueForKey: @ "@ count" จะให้จำนวนคู่ของคีย์ / ค่า
gnasher729

162
if ([[dictionary allKeys] containsObject:key]) {
    // contains key
}

หรือ

if ([dictionary objectForKey:key]) {
    // contains object
}

100
ตัวอย่างหนึ่งในคำตอบนี้ช้า
James Van Boxtel

5
อ่าน: ตัวอย่างหนึ่งในคำตอบนี้ควรถือว่าผิดกฎหมาย (O (n) แทนที่จะเป็น O (1))
Hertzel Guinness

5
ประสิทธิภาพมีความเกี่ยวข้องมาก อาจเป็นเรื่องจริงที่ว่าบรรทัดที่แน่นอนนี้ไม่เกี่ยวข้อง แต่ถ้ามันจะเกิดซ้ำซ้ำแล้วซ้ำเล่าทั้งหมดในทันทีแทนที่จะใช้เวลา n กำลังใช้ n * m และคุณไม่สามารถหาสาเหตุที่โปรแกรมของคุณช้า เกือบทุกอย่างรวดเร็วเพียงครั้งเดียวหรือในกรณีเล็ก ๆ แต่เมื่อโปรแกรมเติบโตโดยใช้โครงสร้างข้อมูลที่ไม่ถูกต้อง (เช่นอาร์เรย์แทนที่จะเป็น dict ในตัวอย่างแรก) จะทำให้คุณเสียค่าใช้จ่ายมาก
Andrew Hoos

2
การตรวจสอบพจนานุกรม (หรือชุด) สำหรับการมีอยู่ของคีย์นั้นคาดว่า O (1) กับกรณีที่แย่ที่สุดของ O (n) ไม่ใช่ O (บันทึก (n)) เอกสารของ Apple อธิบายอย่างชัดเจน
Andrew Hoos

@JoeBlow “ เคลื่อนไหวจุด Mecanim 3D”ดูเหมือนว่าคุณกำลังสับสน Cocoa Touch / Objective-C พร้อม Unity Engine / C # มันเป็นความจริงที่ Unity Engine นั้นไม่มีประสิทธิภาพอย่างมากในแพลตฟอร์มที่รันอยู่ อย่างไรก็ตามมันไม่เป็นความจริงเลยว่าแอพพลิเคชั่น Objective-C / Swift ไม่มีประสิทธิภาพโดยเนื้อแท้และผู้พัฒนา iOS ที่ช่ำชองส่วนใหญ่ไม่ได้ตระหนักถึงประสิทธิภาพของรหัสของพวกเขา สำหรับ“ เฉพาะที่เกี่ยวข้องกับโปรแกรมเมอร์ประสิทธิภาพ (มีชีวิตอยู่ 4 คน)”คุณไม่ได้เป็นผู้พัฒนาเกมอย่างชัดเจน กราฟิกที่ยอดเยี่ยมและการเล่นเกมที่ 60FPS โดยไม่ต้องฆ่าแบตเตอรี่เป็นความท้าทายอย่างต่อเนื่อง
Slipp D. Thompson

98

เวอร์ชันล่าสุดของ Objective-C และ Clang มีรูปแบบที่ทันสมัยสำหรับเรื่องนี้:

if (myDictionary[myKey]) {

}

คุณไม่จำเป็นต้องตรวจสอบความเท่าเทียมกันกับศูนย์เนื่องจากมีเพียงวัตถุที่ไม่ใช่ศูนย์วัตถุประสงค์เท่านั้นที่สามารถเก็บไว้ในพจนานุกรม (หรืออาร์เรย์) และวัตถุ Objective-C ทั้งหมดเป็นค่าความจริง แม้@NO, @0และ[NSNull null]ประเมินผลการศึกษาเป็นความจริง

แก้ไข: Swift ตอนนี้เป็นเรื่อง

สำหรับ Swift คุณจะลองทำสิ่งต่อไปนี้

if let value = myDictionary[myKey] {

}

ไวยากรณ์นี้จะดำเนินการถ้าบล็อกถ้า myKey อยู่ใน dict และถ้าเป็นเช่นนั้นค่าจะถูกเก็บไว้ในตัวแปรค่า โปรดทราบว่าสิ่งนี้ใช้ได้กับค่าที่ผิดพลาดเช่น 0


ขอบคุณสำหรับสิ่งนี้! ฉันแค่อยากรู้อยากเห็น แต่ฉันไม่สามารถหาพฤติกรรมนี้ได้ในเอกสารอ้างอิงผู้พัฒนาคลาสวัตถุประสงค์ c- / library / mac/documentation/Cocoa/Reference/ ...... ฉันเพิ่งตาบอด?
irh

2
ไม่คุณไม่ใช่คนตาบอด มันไม่ได้เน้น แต่มองเห็นได้ที่นี่ (เสียงดังกราว) และที่นี่ (ทันสมัย ​​objc: ด้านล่างสุด) และที่นี่ (คู่มือคอลเลกชัน: พจนานุกรมการค้นหา)
Andrew Hoos


9

เมื่อใช้พจนานุกรม JSON:

#define isNull(value) value == nil || [value isKindOfClass:[NSNull class]]

if( isNull( dict[@"my_key"] ) )
{
    // do stuff
}

8

ฉันชอบคำตอบของเฟอร์นันเดสแม้ว่าคุณจะขอให้มีการ obj สองครั้ง

สิ่งนี้ควรทำ (มากกว่าหรือน้อยกว่าเช่นเดียวกับ Martin's A)

id obj;

if ((obj=[dict objectForKey:@"blah"])) {
   // use obj
} else {
   // Do something else like creating the obj and add the kv pair to the dict
}

Martin และคำตอบนี้ใช้ได้กับ iPad2 iOS 5.0.1 9A405


5

gotcha ที่น่ารังเกียจอย่างหนึ่งซึ่งเพิ่งเสียเวลาเล็กน้อยในการดีบัก - คุณอาจพบว่าตัวเองได้รับแจ้งจากการป้อนอัตโนมัติเพื่อลองใช้ doesContainซึ่งดูเหมือนว่าจะใช้งานได้

ยกเว้นdoesContainใช้การเปรียบเทียบรหัสแทนการเปรียบเทียบกัญชาที่ใช้โดยดังนั้นหากคุณมีพจนานุกรมด้วยปุ่มสตริงมันจะไม่กลับไปobjectForKeydoesContain

NSMutableDictionary* keysByName = [[NSMutableDictionary alloc] init];
keysByName[@"fred"] = @1;
NSString* test = @"fred";

if ([keysByName objectForKey:test] != nil)
    NSLog(@"\nit works for key lookups");  // OK
else
    NSLog(@"\nsod it");

if (keysByName[test] != nil)
    NSLog(@"\nit works for key lookups using indexed syntax");  // OK
else
    NSLog(@"\nsod it");

if ([keysByName doesContain:@"fred"])
    NSLog(@"\n doesContain works literally");
else
    NSLog(@"\nsod it");  // this one fails because of id comparison used by doesContain


5

ใช่. ข้อผิดพลาดประเภทนี้เกิดขึ้นบ่อยมากและทำให้แอปขัดข้อง ดังนั้นฉันใช้เพื่อเพิ่ม NSDictionary ในแต่ละโครงการดังนี้:

//.h รหัสไฟล์:

@interface NSDictionary (AppDictionary)

- (id)objectForKeyNotNull : (id)key;

@end

//.m รหัสของไฟล์เป็นดังนี้

#import "NSDictionary+WKDictionary.h"

@implementation NSDictionary (WKDictionary)

 - (id)objectForKeyNotNull:(id)key {

    id object = [self objectForKey:key];
    if (object == [NSNull null])
     return nil;

    return object;
 }

@end

ในรหัสคุณสามารถใช้ดังต่อไปนี้:

NSStrting *testString = [dict objectForKeyNotNull:@"blah"];


3

เนื่องจากไม่มีศูนย์ไม่สามารถจัดเก็บในโครงสร้างข้อมูลของมูลนิธิได้ในNSNullบางครั้งเพื่อเป็นตัวแทนnilของ เนื่องจากNSNullเป็นวัตถุซิงเกิลคุณสามารถตรวจสอบว่าNSNullเป็นค่าที่จัดเก็บในพจนานุกรมหรือไม่โดยใช้การเปรียบเทียบตัวชี้โดยตรง:

if ((NSNull *)[user objectForKey:@"myKey"] == [NSNull null]) { }

1
ไม่ได้ผลเมื่อฉันใช้กับ NSMutableArray เป็นวัตถุสำหรับคีย์ของฉัน
pa12

4
ทำไมสิ่งนี้ถึงถูกโหวตขึ้น? มันผิดธรรมดา การตรวจสอบนี้จะกลับมาจริงถ้าเดี่ยวเช่นได้รับการเก็บไว้ในพจนานุกรมเป็นค่าสำหรับคีย์NSNull @"myKey"นั่นเป็นสิ่งที่แตกต่างไปอย่างสิ้นเชิงกับกุญแจที่@"myKey"ไม่ได้อยู่ในพจนานุกรม
Mark Amery

เนื่องจากยังคงมีห้าคะแนนในขณะที่ผิดทั้งหมดฉันสามารถทำซ้ำสิ่งที่ Mark พูดว่า: รหัสนี้ทดสอบว่าพจนานุกรมมีคีย์ที่มีค่า Null หรือไม่ซึ่งแตกต่างอย่างสิ้นเชิงจากการไม่มีคีย์เลย
gnasher729

มันเป็น "ผิดอย่างสมบูรณ์ แต่ชี้ไปที่ข้อมูลที่น่าสนใจ"
Fattie

คำตอบนี้ได้รับการแก้ไขเพื่อชี้แจงสิ่งที่มันทำ (ตรวจสอบ NSNull ใน dict) และสิ่งที่มันไม่ทำ (ตรวจสอบค่าใน dict)
Andrew Hoos

2

วิธีแก้ปัญหาสำหรับ swift 4.2

ดังนั้นหากคุณต้องการตอบคำถามว่าพจนานุกรมมีรหัสหรือไม่ให้ถาม:

let keyExists = dict[key] != nil

ถ้าคุณต้องการค่าและคุณรู้ว่าพจนานุกรมมีกุญแจพูด:

let val = dict[key]!

แต่ถ้าตามปกติคุณไม่ทราบว่ามันมีรหัสหรือไม่ - คุณต้องการดึงข้อมูลและใช้มัน แต่ถ้ามีอยู่ - ให้ใช้if letดังนี้:

if let val = dict[key] {
    // now val is not nil and the Optional has been unwrapped, so use it
}

1

ฉันขอแนะนำให้คุณเก็บผลการค้นหาในตัวแปร temp ทดสอบว่าตัวแปร temp เป็นศูนย์หรือไม่จากนั้นใช้ ด้วยวิธีนี้คุณจะไม่มองวัตถุเดียวกันสองครั้ง:

id obj = [dict objectForKey:@"blah"];

if (obj) {
   // use obj
} else {
   // Do something else
}

1

ดังที่ Adirael แนะนำobjectForKeyให้ตรวจสอบการมีอยู่ของคีย์ แต่เมื่อคุณโทรobjectForKeyในพจนานุกรมที่ไม่มีค่าใช้จ่ายแอปจะขัดข้องดังนั้นฉันจึงแก้ไขจากวิธีต่อไปนี้

- (instancetype)initWithDictionary:(NSDictionary*)dictionary {
id object = dictionary;

if (dictionary && (object != [NSNull null])) {
    self.name = [dictionary objectForKey:@"name"];
    self.age = [dictionary objectForKey:@"age"];
}
return self;

}


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.