Bir NSDictionary veya NSMutableDictionary bir anahtar içerip içermediğini nasıl kontrol edebilirim?


456

Bir diksiyonun bir anahtarı olup olmadığını kontrol etmem gerekiyor. Nasıl?


4
(Sadece burada googling yapan herkes için. Bunun çok eski bir soru olduğunu unutmayın . Aşağıdaki SaintMacintosh cevabı en son teknoloji, bu QA'nın beş yıl ilerisinde. Umarım yardımcı olur.)
Fattie

1
Aslında, Andy Dent'in yanıtı en son teknolojiyi ve daha fazla bağlamı da veriyor. Ve bunu SaintMacintosh'tan daha önce yaptı. Kendinize biraz daha aşağı kaydırma bir iyilik yapın.
Peter Kämpf

1
Şunu kullanır: keysByName [test]! = Nil! = Nil kontrolü gereksizdir ve IMHO daha az okunabilir. Sadece sözdizimini arayan insanlar için TL; DR sürümünü paylaşmak istedim.
Andrew Hoos

@SaintMacintosh ile hemfikirim. onun yanıtı çok daha özlü.
Steve Schwarcz

Eğer kontrol etmek isterseniz NSDictionaryherhangi bir tuşa (spesifik olmayan) içeren kullanmanız gereken [dictionary allKeys].count == 0varsa countolduğunu 0hiçbir anahtar vardır NSDictionary.
Aleksander Azizi

Yanıtlar:


768

objectForKey bir anahtar yoksa sıfır döndürür.


29
Peki ya anahtar varsa, ancak karşılık gelen değer sıfırsa ne olur?
Fyodor Soikin

232
Bu mümkün değil. Bir NSDictionary'e nil ekleyemezsiniz. Bunun [NSNull null]yerine kullanmak zorunda kalacaksınız.
Ole Begemann

10
nil değeri eklemeye çalışırsanız, @fyodor bir nsdictionay bir NSInvalidArgumentException özel durumu atar, bu nedenle hiçbir zaman bir anahtarın bulunduğu bir durum olmamalıdır, ancak karşılık gelen değer nil'dir.
Brad App Guy

3
ValueForKey'i kullanmak istemiyor musunuz, çünkü bu gerekirse objectForKey'i çağırır mı?
Raffi Khatchadourian

6
Kesinlikle ASLA bir JSON sözlüğü için valueForKey kullanmak istemiyorum. JSON anahtar olarak herhangi bir dize içerebilir çünkü . Örneğin, anahtar olarak "@ sayım" içeriyorsa, objectForKey: @ "@ count" doğru değeri verir, ancak valueForKey: @ "@ count" anahtar / değer çifti sayısını verir.
gnasher729

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

veya

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

100
Bu cevaptaki birinci örnek yavaş.
James Van Boxtel

5
okuyun: bu yanıttaki örnek bir kişi O (1) yerine yasadışı kabul edilmelidir (O ​​(n))
Hertzel Guinness

5
performans çok önemlidir. Bu kesin çizginin alakasız olduğu çok doğru olabilir, ancak n kez tekrarlanacaksa, n * m alması zaman almak yerine ani olur ve programınızın neden yavaş olduğunu anlayamazsınız. Hemen hemen her şey bir kez veya küçük durumlarda hızlıdır. Ancak programlar yanlış veri yapısını kullanarak büyüdükçe (ilk örnekte dikte yerine dizi gibi) size büyük maliyet getirecektir.
Andrew Hoos

2
Bir sözlüğün (veya kümenin) bir anahtar olup olmadığını kontrol etmek O (1) en kötü O (n) durumundadır. O değil (log (n)). Apple'ın belgeleri bunu açıkça açıklıyor.
Andrew Hoos

@JoeBlow “3D Mecanim noktalarını canlandırın” Görünüşe göre Cocoa Touch / Objective-C ile Unity Engine / C # karıştırıyorsunuz. Unity Engine'in üzerinde çalıştığı platformlarda son derece verimsiz olduğu doğrudur. Bununla birlikte, Objective-C / Swift uygulamalarının doğası gereği verimsiz olduğu veya çoğu deneyimli iOS geliştiricisinin kodlarının verimliliğini aktif olarak tanımadığı doğru değildir. Gelince “(4 oturma) performans programcılar için sadece ilgili” - açıkça bir oyun geliştiricisi değiliz. Pili öldürmeden 60FPS'de harika grafikler ve oynanış sürekli bir sorundur.
Slipp D. Thompson

98

Objective-C ve Clang'ın daha yeni sürümleri bunun için modern bir sözdizimine sahiptir:

if (myDictionary[myKey]) {

}

Nil ile eşitliği kontrol etmek zorunda değilsiniz, çünkü sözlüklerde (veya dizilerde) sadece nil olmayan Objective-C nesneleri saklanabilir. Ve tüm Objective-C nesneleri gerçek değerlerdir. Hatta @NO,, @0ve [NSNull null]doğru olarak değerlendir.

Edit: Swift artık bir şey.

Swift için aşağıdakine benzer bir şey denersiniz

if let value = myDictionary[myKey] {

}

Bu sözdizimi yalnızca, myKey dict'te ise ve öyleyse değer value değişkeninde saklanırsa if bloğunu yürütür. Bunun 0 gibi çift değerler için de işe yaradığını unutmayın.


Bunun için teşekkürler! Sadece merak ediyorum, ama bu davranışı objektif-c sınıfı referans geliştirici içinde bulamıyorum.apple.com/library/mac/documentation/Cocoa/Reference/… AM Sadece kör mü?
irh

2
Hayır kör değilsin. Vurgulanmamıştır. Ama burada görülebilir (clang) ve burada (modern objc: çok altta) ve burada (koleksiyon rehberi: arama sözlüğü)
Andrew Hoos

22
if ([mydict objectForKey:@"mykey"]) {
    // key exists.
}
else
{
    // ...
}

9

JSON sözlüklerini kullanırken:

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

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

8

İki kez obj isteseniz de Fernandes'nin cevabını seviyorum.

Bu da yapmalıdır (Martin A ile aşağı yukarı aynı).

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 ve bu cevap her ikisi de iPad2 iOS 5.0.1 9A405'te çalışıyor


5

Sadece biraz hata ayıklama zamanını boşa harcanan çok kötü bir gotcha - kendinizi doesContainişe yarar görünüyor kullanmayı denemek için otomatik tamamlandı tarafından istenebilir bulabilirsiniz .

Dışında, doesContaintarafından kullanılan karma karşılaştırması yerine bir kimlik karşılaştırması kullanır, bu objectForKeynedenle dize tuşlarına sahip bir sözlüğünüz varsa, NO değerine a döndürür 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

5

Swift'i kullanmak şöyle olur:

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

5

Evet. Bu tür hatalar çok yaygındır ve uygulama kilitlenmesine yol açar. Bu yüzden aşağıdaki gibi her projeye NSDictionary eklemek için kullanın:

//.h dosya kodu:

@interface NSDictionary (AppDictionary)

- (id)objectForKeyNotNull : (id)key;

@end

//.m dosya kodu aşağıdaki gibidir

#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

Kodda aşağıdaki gibi kullanabilirsiniz:

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

3

NSDictionary anahtarının varlığını kontrol etmek için:

if([dictionary objectForKey:@"Replace your key here"] != nil)
    NSLog(@"Key Exists");
else
    NSLog(@"Key not Exists");

1
Bu gerçekten bu mevcut cevabın tekrarı .
Pang

3

Nil, Vakıf veri yapılarında saklanamayacağı NSNulliçin bazen a nil. Tek NSNullbir nesne olduğundan NSNull, doğrudan işaretçi karşılaştırmasını kullanarak sözlükte saklanan değerin olup olmadığını kontrol edebilirsiniz :

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

1
NSMutableArray ile anahtarım için nesne olarak kullandığımda işe yaramadı.
pa12

4
Bu neden yeryüzünde yükseldi? Sadece yanlış. Singleton NSNullörneği sözlükte anahtarın değeri olarak saklandıysa bu denetim true değerini döndürür @"myKey". Bu @"myKey", sözlükte olmamak için anahtardan tamamen farklı bir şeydir - aslında ikisi birbirini dışlar.
Mark Amery

Bu tamamen yanlışken hala beş oy olduğundan, sadece Mark'ın söylediklerini tekrarlayabilirim: Bu kod, sözlüğün anahtar içermeyenden tamamen farklı olan boş değerli bir anahtar içerip içermediğini test eder.
gnasher729

"Tamamen yanlış, ama ilginç bilgilere işaret ediyor"
Fattie

Bu cevap, ne yaptığını (bir dikte NSNull'u kontrol edin) ve ne yapmadığını (bir
dikte

2

Hızlı 4.2 için çözüm

Dolayısıyla, sözlüğün anahtarı içerip içermediğini soruyu yanıtlamak istiyorsanız, şunu sorun:

let keyExists = dict[key] != nil

Değeri istiyorsanız ve sözlüğün anahtarı içerdiğini biliyorsanız şunu söyleyin:

let val = dict[key]!

Ancak, genellikle olduğu gibi, anahtarın içerdiğini bilmiyorsanız - onu almak ve kullanmak istiyorsunuz, ancak sadece varsa - o zaman şöyle bir şey kullanın if let:

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

1

Aramanın sonucunu bir temp değişkeninde saklamanızı, temp değişkeninin nil olup olmadığını test etmenizi ve daha sonra kullanmanızı öneririm. Bu şekilde aynı nesneyi iki kez görmezsiniz:

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

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

1

Adirael'in objectForKeyanahtar varlığını kontrol etmesini önerdiği gibi objectForKeynullable sözlükte aradığınızda , uygulama çöküyor , bu yüzden bunu aşağıdaki yoldan çözdüm .

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

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

}


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.