Bagaimana cara memeriksa apakah NSDictionary atau NSMutableDictionary berisi kunci?

456

Saya perlu memeriksa apakah dict memiliki kunci atau tidak. Bagaimana?

profilProfile dontWatch
sumber
4
(Hanya untuk siapa pun yang googling ke sini. Perhatikan bahwa ini adalah pertanyaan yang sangat lama . Jawaban SaintMacintosh di bawah ini adalah yang paling canggih, lima tahun lebih cepat dari QA ini. Semoga ini membantu.)
Fattie
1
Sebenarnya, jawaban Andy Dent juga memberikan keadaan seni, dan lebih banyak konteks. Dan itu melakukan ini lebih awal dari SaintMacintosh. Bantulah diri Anda sedikit gulir ke bawah.
Peter Kämpf
1
Ia menggunakan: keysByName [test]! = Nil the! = Nil check redundan dan IMHO kurang dapat dibaca. Saya hanya ingin membagikan TL; versi DR untuk orang yang mencari sintaks.
Andrew Hoos
Saya setuju dengan @SaintMacintosh. jawabannya jauh lebih ringkas.
Steve Schwarcz
Jika Anda ingin memeriksa apakah NSDictionarymengandung kunci (non-spesifik) Anda harus menggunakan [dictionary allKeys].count == 0Jika countini 0tidak ada kunci di NSDictionary.
Aleksander Azizi

Jawaban:

768

objectForKey akan mengembalikan nol jika kunci tidak ada.

Adirael
sumber
29
Dan bagaimana jika kuncinya ada, tetapi nilainya sesuai adalah nihil?
Fyodor Soikin
232
Itu tidak mungkin. Anda tidak dapat menambahkan nihil ke NSDictionary. Anda harus menggunakannya [NSNull null]sebagai gantinya.
Ole Begemann
10
@fyodor suatu nsdictionay akan melempar NSInvalidArgumentException jika Anda mencoba untuk memasukkan nilai nil, jadi seharusnya tidak pernah ada kasus di mana kunci ada, tetapi nilai yang sesuai adalah nil.
Brad The App Guy
3
Tidakkah Anda ingin menggunakan valueForKey, karena itu akan memanggil objectForKey jika perlu?
Raffi Khatchadourian
6
Anda benar-benar TIDAK PERNAH ingin menggunakan valueForKey untuk kamus JSON. Itu karena JSON dapat berisi string apa pun sebagai kunci. Misalnya, jika berisi "@count" sebagai kunci, maka objectForKey: @ "@ count" akan memberikan nilai yang benar, tetapi valueForKey: @ "@ count" akan memberikan jumlah pasangan kunci / nilai.
gnasher729
162
if ([[dictionary allKeys] containsObject:key]) {
    // contains key
}

atau

if ([dictionary objectForKey:key]) {
    // contains object
}
Aleksejs Mjaliks
sumber
100
Contoh satu dalam jawaban ini lambat.
James Van Boxtel
5
baca: contoh satu dalam jawaban ini harus dianggap ilegal (O (n) dan bukan O (1))
Hertzel Guinness
5
kinerja sangat relevan. Mungkin sangat benar bahwa baris yang tepat ini tidak relevan, tetapi jika itu akan diulangi n kali maka tiba-tiba alih-alih butuh n waktu mengambil n * m dan Anda tidak dapat mencari tahu mengapa program Anda lambat. Hampir semuanya cepat sekali atau dalam kasus kecil. Tetapi ketika program tumbuh menggunakan struktur data yang salah (seperti array bukan dict dalam contoh pertama) akan berakhir dengan biaya besar.
Andrew Hoos
2
Memeriksa kamus (atau set) untuk keberadaan kunci diharapkan O (1) dengan kasus terburuk O (n). Bukan O (log (n)). Dokumentasi Apple dengan jelas menjelaskan hal ini.
Andrew Hoos
@ JoBlow “menghidupkan titik 3D Mecanim” Sepertinya Anda membingungkan Cocoa Touch / Objective-C dengan Unity Engine / C #. Memang benar bahwa Unity Engine sangat tidak efisien pada platform yang dijalankannya. Namun, sama sekali tidak benar bahwa aplikasi Objective-C / Swift secara inheren tidak efisien, atau bahwa sebagian besar pengembang iOS yang berpengalaman tidak secara aktif menyadari efisiensi kode mereka. Adapun "hanya relevan dengan programmer kinerja (4 hidup)" - Anda jelas bukan pengembang game. Grafis & gameplay bagus pada 60FPS tanpa membunuh baterai adalah tantangan terus menerus.
Slipp D. Thompson
98

Versi Objective-C dan Clang yang lebih baru memiliki sintaksis modern untuk ini:

if (myDictionary[myKey]) {

}

Anda tidak perlu memeriksa kesetaraan dengan nil, karena hanya objek Objective-C yang tidak nihil yang dapat disimpan dalam kamus (atau array). Dan semua objek Objective-C adalah nilai kebenaran. Merata @NO, @0dan [NSNull null]mengevaluasi sebagai benar.

Sunting: Swift sekarang menjadi sesuatu.

Untuk Swift Anda akan mencoba sesuatu seperti yang berikut ini

if let value = myDictionary[myKey] {

}

Sintaks ini hanya akan mengeksekusi blok if jika myKey ada dalam dict dan jika ya maka nilai tersebut disimpan dalam variabel value. Perhatikan bahwa ini berfungsi bahkan untuk nilai falsey seperti 0.

Andrew Hoos
sumber
Terima kasih untuk ini! Saya hanya ingin tahu, tetapi saya tidak dapat menemukan perilaku ini didokumentasikan di developer referensi-c kelas objektif.apple.com/library/mac/documentation/Cocoa/Reference/… AM Saya hanya buta?
irh
2
Tidak, kamu tidak buta. Itu tidak ditekankan. Tapi terlihat di sini (dentang) dan di sini (modern objc: paling bawah) dan di sini (panduan koleksi: kamus pencarian)
Andrew Hoos
22
if ([mydict objectForKey:@"mykey"]) {
    // key exists.
}
else
{
    // ...
}
ChristopheD
sumber
9

Saat menggunakan kamus JSON:

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

if( isNull( dict[@"my_key"] ) )
{
    // do stuff
}
Ratata Tata
sumber
8

Saya suka jawaban Fernandes meskipun Anda meminta keberatan dua kali.

Ini juga harus dilakukan (kurang lebih sama dengan Martin 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 dan jawaban ini berfungsi pada iPad2 iOS 5.0.1 9A405

q231950
sumber
5

Satu gotcha yang sangat jahat yang hanya menghabiskan sedikit waktu saya untuk debugging - Anda mungkin menemukan diri Anda diminta oleh pelengkapan otomatis untuk mencoba menggunakan doesContainyang tampaknya berfungsi.

Kecuali, doesContaingunakan perbandingan id daripada perbandingan hash yang digunakan oleh objectForKeyjadi jika Anda memiliki kamus dengan kunci string, ia akan mengembalikan TIDAK ke a doesContain.

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
Andy Dent
sumber
5

Menggunakan Swift, itu akan menjadi:

if myDic[KEY] != nil {
    // key exists
}
rsc
sumber
5

Iya. Kesalahan semacam ini sangat umum dan menyebabkan aplikasi crash. Jadi saya gunakan untuk menambahkan NSDictionary di setiap proyek seperti di bawah ini:

//.h kode file:

@interface NSDictionary (AppDictionary)

- (id)objectForKeyNotNull : (id)key;

@end

//.m kode file adalah seperti di bawah ini

#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

Dalam kode Anda dapat menggunakan seperti di bawah ini:

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

Untuk memeriksa keberadaan kunci di NSDictionary:

if([dictionary objectForKey:@"Replace your key here"] != nil)
    NSLog(@"Key Exists");
else
    NSLog(@"Key not Exists");
Aamir
sumber
1
Ini benar-benar hanya pengulangan dari jawaban yang ada ini .
Pang
3

Karena nil tidak dapat disimpan dalam struktur data Foundation NSNullterkadang mewakili a nil. Karena NSNulladalah objek tunggal yang dapat Anda periksa untuk melihat apakah NSNullnilai disimpan dalam kamus dengan menggunakan perbandingan pointer langsung:

if ((NSNull *)[user objectForKey:@"myKey"] == [NSNull null]) { }
Fernandes
sumber
1
Tidak berhasil ketika saya menggunakannya dengan NSMutableArray sebagai objek untuk kunci saya.
pa12
4
Mengapa ini dibalik? Itu salah sekali. Pemeriksaan ini akan mengembalikan true jika NSNullinstance tunggal telah disimpan dalam kamus sebagai nilai untuk kunci @"myKey". Itu hal yang sama sekali berbeda dengan kunci yang @"myKey"tidak ada dalam kamus - memang keduanya saling eksklusif.
Mark Amery
Karena ini masih memiliki lima suara sementara benar-benar salah, saya hanya dapat mengulangi apa yang dikatakan Mark: Kode ini menguji apakah kamus berisi kunci dengan nilai nol, yang sama sekali berbeda dengan tidak berisi kunci sama sekali.
gnasher729
"Benar-benar salah, tetapi menunjukkan informasi yang menarik"
Fattie
Jawaban ini telah diedit untuk memperjelas apa yang dilakukannya (periksa NSNull dalam suatu dict) dan apa yang tidak dilakukannya (periksa nilai dalam dict)
Andrew Hoos
2

Solusi untuk swift 4.2

Jadi, jika Anda hanya ingin menjawab pertanyaan apakah kamus berisi kunci, tanyakan:

let keyExists = dict[key] != nil

Jika Anda menginginkan nilainya dan Anda tahu kamus berisi kunci, katakan:

let val = dict[key]!

Tetapi jika, seperti biasanya terjadi, Anda tidak tahu itu berisi kunci - Anda ingin mengambil dan menggunakannya, tetapi hanya jika ada - maka gunakan sesuatu seperti if let:

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

Saya sarankan Anda menyimpan hasil pencarian dalam variabel temp, menguji apakah variabel temp adalah nil dan kemudian menggunakannya. Dengan begitu Anda tidak melihat objek yang sama dua kali:

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

if (obj) {
   // use obj
} else {
   // Do something else
}
Martin
sumber
1

Seperti yang disarankan Adirael objectForKeyuntuk memeriksa keberadaan kunci tetapi ketika Anda memanggil objectForKeydalam kamus nullable, aplikasi jadi macet jadi saya memperbaiki ini dari mengikuti cara.

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

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

}

Aleem
sumber
0
if ([MyDictionary objectForKey:MyKey]) {
      // "Key Exist"
} 
saurabh rathod
sumber
Ini benar-benar hanya pengulangan dari jawaban yang ada ini .
Pang