Làm cách nào để kiểm tra xem một NSDipedia hoặc NSMutableDixi có chứa khóa không?


456

Tôi cần kiểm tra xem một dict có khóa hay không. Làm sao?


4
(Chỉ dành cho bất kỳ ai googling ở đây. Lưu ý rằng đây là một câu hỏi rất . Câu trả lời của SaintMacffy dưới đây là tình trạng của nghệ thuật, nó đi trước năm năm của QA này. Hy vọng nó có ích.)
Fattie

1
Trên thực tế, câu trả lời của Andy Dent cũng đưa ra trạng thái của nghệ thuật, và nhiều bối cảnh hơn. Và nó đã làm điều này sớm hơn SaintMacffy. Làm cho mình một ưu tiên một cuộn xuống nhiều hơn một chút.
Peter Kämpf

1
Anh ta sử dụng: KeysByName [test]! = Nil kiểm tra! = Nil là dự phòng và IMHO ít đọc hơn. Tôi chỉ muốn chia sẻ phiên bản TL; DR cho những người tìm kiếm cú pháp.
Andrew Hoos

Tôi đồng ý với @SaintMacffy. Câu trả lời của anh ấy ngắn gọn hơn nhiều.
Steve Schwarcz

Nếu bạn muốn kiểm tra xem NSDictionarycó chứa khóa nào không (không cụ thể) bạn nên sử dụng [dictionary allKeys].count == 0Nếucount0không có phím trong NSDictionary.
Aleksander Azizi

Câu trả lời:


768

objectForKey sẽ trả về nil nếu khóa không tồn tại.


29
Và nếu khóa tồn tại, nhưng giá trị tương ứng của nó là 0 thì sao?
Fyodor Soikin

232
Đó là không thể. Bạn không thể thêm số không vào NSDipedia. Bạn sẽ phải sử dụng [NSNull null]thay thế.
Ole Begemann

10
@fyodor một nsdictionay sẽ ném NSInvalidArgumentException nếu bạn cố gắng chèn một giá trị nil, vì vậy sẽ không bao giờ có trường hợp khóa tồn tại, nhưng giá trị tương ứng là không.
Brad The App Guy

3
Bạn không muốn sử dụng valueForKey, vì điều đó sẽ gọi objectForKey nếu cần thiết?
Raffi Khatchadourian

6
Bạn tuyệt đối KHÔNG BAO GIỜ KHÔNG BAO GIỜ muốn sử dụng valueForKey cho từ điển JSON. Đó là bởi vì JSON có thể chứa bất kỳ chuỗi nào làm khóa. Ví dụ: nếu nó chứa "@count" làm khóa, thì objectForKey: @ "@ Count" sẽ cho giá trị đúng, nhưng valueForKey: @ "@ Count" sẽ cho số lượng cặp khóa / giá trị.
gnasher729

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

hoặc là

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

100
Ví dụ một trong câu trả lời này là chậm.
James Van Boxtel

5
đọc: ví dụ một trong câu trả lời này nên được coi là bất hợp pháp (O (n) thay vì O (1))
Hertzel Guinness

5
hiệu suất là rất phù hợp. Có thể rất đúng là dòng chính xác này không liên quan, nhưng nếu nó được lặp đi lặp lại n lần thì tất cả thay vì mất thời gian, nó mất n * m và bạn không thể hiểu tại sao chương trình của bạn chậm. Hầu như mọi thứ đều nhanh một lần hoặc trong các trường hợp nhỏ. Nhưng khi các chương trình phát triển bằng cách sử dụng cấu trúc dữ liệu sai (như mảng thay vì dict trong ví dụ đầu tiên) sẽ khiến bạn phải trả giá đắt.
Andrew Hoos

2
Việc kiểm tra từ điển (hoặc bộ) để biết sự tồn tại của khóa được mong đợi là O (1) với trường hợp xấu nhất là O (n). Không phải O (log (n)). Tài liệu của Apple giải thích rõ ràng điều này.
Andrew Hoos

@JoeBlow Hồi làm sinh động các chấm Mecanim 3D của Âm thanh Nghe có vẻ như bạn đang nhầm lẫn giữa Ca cao cảm ứng / Objective-C với Unity Engine / C #. Đúng là Unity Engine hoạt động kém hiệu quả trên các nền tảng mà nó chạy. Tuy nhiên, hoàn toàn không đúng khi các ứng dụng Objective-C / Swift vốn không hiệu quả, cũng như hầu hết các nhà phát triển iOS dày dạn không chủ động nhận thức về hiệu quả của mã của họ. Đối với chỉ có liên quan đến các lập trình viên hiệu suất (4 người sống), bạn rõ ràng không phải là nhà phát triển trò chơi. Đồ họa và lối chơi tuyệt vời ở 60FPS mà không giết được pin là một thách thức liên tục.
Slipp D. Thompson

98

Các phiên bản gần đây hơn của Objective-C và Clang có cú pháp hiện đại cho việc này:

if (myDictionary[myKey]) {

}

Bạn không phải kiểm tra sự bằng nhau với nil, bởi vì chỉ các đối tượng Objective-C không phải nil mới có thể được lưu trữ trong từ điển (hoặc mảng). Và tất cả các đối tượng Objective-C là giá trị trung thực. Thậm chí @NO,@0[NSNull null]đánh giá là đúng.

Chỉnh sửa: Swift bây giờ là một điều.

Đối với Swift, bạn sẽ thử một cái gì đó như sau

if let value = myDictionary[myKey] {

}

Cú pháp này sẽ chỉ thực thi khối if nếu myKey nằm trong dict và nếu có thì giá trị được lưu trong biến giá trị. Lưu ý rằng điều này hoạt động cho các giá trị thậm chí falsey như 0.


Cám ơn vì cái này! Tôi chỉ tò mò, nhưng tôi không thể tìm thấy hành vi này được ghi lại trong tài liệu tham khảo của nhà phát triển lớp khách quan c.apple.com / l Library / mac / documentation / Coloa / Reference / Lỗi Tôi chỉ bị mù?
irh

2
Không, bạn không mù quáng. Nó không được nhấn mạnh. Nhưng có thể nhìn thấy ở đây (tiếng kêu) và ở đây (objc hiện đại: rất thấp) và ở đây (hướng dẫn bộ sưu tập: từ điển tìm kiếm)
Andrew Hoos

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

9

Khi sử dụng từ điển JSON:

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

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

8

Tôi thích câu trả lời của Fernandes mặc dù bạn yêu cầu obj hai lần.

Điều này cũng nên làm (ít nhiều giống như A của Martin).

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
}

Cả Martin và câu trả lời này đều hoạt động trên iPad2 iOS 5.0.1 9A405


5

Một vấn đề rất khó chịu chỉ làm mất một chút thời gian của tôi để gỡ lỗi - bạn có thể thấy mình được nhắc nhở bằng cách tự động hoàn thành để thử sử dụng doesContain dường như hoạt động.

Ngoại trừ, doesContainsử dụng so sánh id thay vì so sánh băm được sử dụng bởi objectForKeyvì vậy nếu bạn có một từ điển với các khóa chuỗi, nó sẽ trả về NO cho 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

5

Sử dụng Swift, nó sẽ là:

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

5

Đúng. Loại lỗi này rất phổ biến và dẫn đến sự cố ứng dụng. Vì vậy, tôi sử dụng để thêm NSDipedia trong mỗi dự án như sau:

Mã tập tin //.h:

@interface NSDictionary (AppDictionary)

- (id)objectForKeyNotNull : (id)key;

@end

Mã tệp //.m như dưới đây

#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

Trong mã bạn có thể sử dụng như dưới đây:

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

3

Để kiểm tra sự tồn tại của khóa trong NSDipedia:

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

1
Đây thực sự chỉ là một sự lặp lại của câu trả lời hiện có này .
Pang

3

Bởi vì nil không thể được lưu trữ trong cấu trúc dữ liệu Foundation NSNullđôi khi để thể hiện a nil. Bởi vì NSNulllà một đối tượng đơn lẻ, bạn có thể kiểm tra xem liệu NSNullgiá trị được lưu trong từ điển bằng cách sử dụng so sánh con trỏ trực tiếp:

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

1
Tôi đã không làm việc khi tôi sử dụng nó với NSMutableArray làm đối tượng cho khóa của mình.
pa12

4
Tại sao trên trái đất này đã được nâng cấp? Nó hoàn toàn sai. Kiểm tra này sẽ trả về true nếu đối tượng singleton NSNullđã được lưu trong từ điển làm giá trị cho khóa @"myKey". Đó là một điều hoàn toàn khác với chìa khóa @"myKey"không có trong từ điển - thực sự cả hai loại trừ lẫn nhau.
Đánh dấu Amery

Vì điều này vẫn có năm phiếu trong khi hoàn toàn sai, tôi chỉ có thể lặp lại những gì Mark nói: Mã này kiểm tra xem từ điển có chứa khóa có giá trị null hay không, hoàn toàn khác với không chứa khóa.
gnasher729

Đó là "hoàn toàn sai, nhưng chỉ ra thông tin thú vị"
Fattie

Câu trả lời này đã được chỉnh sửa để làm rõ những gì nó làm (kiểm tra NSNull trong một lệnh) và những gì nó không làm (kiểm tra giá trị trong một lệnh)
Andrew Hoos

2

Giải pháp cho swift 4.2

Vì vậy, nếu bạn chỉ muốn trả lời câu hỏi liệu từ điển có chứa khóa hay không, hãy hỏi:

let keyExists = dict[key] != nil

Nếu bạn muốn giá trị và bạn biết từ điển chứa khóa, hãy nói:

let val = dict[key]!

Nhưng nếu, như thường xảy ra, bạn không biết nó chứa khóa - bạn muốn lấy nó và sử dụng nó, nhưng chỉ khi nó tồn tại - thì hãy sử dụng cái gì đó như if let:

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

1

Tôi khuyên bạn nên lưu trữ kết quả tra cứu trong biến temp, kiểm tra xem biến temp có phải không và sau đó sử dụng nó. Bằng cách đó, bạn không nhìn cùng một đối tượng lên hai lần:

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

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

1

Như Adirael đề nghị objectForKeykiểm tra sự tồn tại của khóa nhưng khi bạn gọi objectForKeytrong từ điển nullable, ứng dụng bị lỗi nên tôi đã sửa lỗi này theo cách sau.

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

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

}


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.