检查NSDictionary中的键是否为空。

17

我搜索了如何检查NSDictionary中的键是否存在,并找到了解决方案。但是它仍然抛出一个错误,显示添加了null值到键中。我不确定我的代码是否正确。如果有人对此有任何想法可以帮助我。

NSDictionary *result;
id myImageURL = [result objectForKey:@"url"];
if ((NSNull *)myImageURL == [NSNull null])
    myImageURL = @"";

id myImage = [result objectForKey:@"image"];
if ((NSNull *)myImage == [NSNull null])
    myImage = @"";

检查是否为null,如果是,则不添加任何内容,如果不是,则添加该值。但它仍然给我一个错误,不知道为什么。

/****OUTPUT*****/

2011-08-11 14:56:06.668 Tab_Table_Win[6510:207] RESULTS : {
image = "<UIImage: 0xbc332c0>";
url = "http://a3.twimg.com/profile_images/999228511/normal.jpg";
}

2011-08-11 14:56:06.669 Tab_Table_Win[6510:207] url : http://a3.twimg.com/profile_images/999228511/normal.jpg
2011-08-11 14:56:06.670 Tab_Table_Win[6510:207] IMage : <UIImage: 0xbc332c0>

/*****Breaks Here ***/

2011-08-11 14:56:06.876 Tab_Table_Win[6510:207] RESULTS : {
}
2011-08-11 14:56:06.878 Tab_Table_Win[6510:207] url : (null)
2011-08-11 14:56:06.879 Tab_Table_Win[6510:207] IMage : (null)
2011-08-11 14:56:06.881 Tab_Table_Win[6510:207] *** Terminating app due to uncaught    exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary setObject:forKey:]: attempt to insert nil key'

它给出了什么精确的错误信息?是哪一行代码出了问题? - Chuck
通过将其发送到一个ID再进行强制转换,您浪费了内存,尽管非常少。您可以一行完成它。我希望iOS有一个像.net那样的keysExist属性。 - Nick Turner
13个回答

14

正确答案是:

NSDictionary *result;
NSURL *myImageURL = [result objectForKey:@"url"];
UIImage *myImage = [result objectForKey:@"image"];

/**** Correct way ****/
if (myImageURL != nil && myImage != nil) {
    [images setObject:myImage forKey:myImageURL];
}

非常感谢您的解释。


2
你能解释一下吗? - lifemoveson

14

Tommy解释得非常好。

我的建议是创建NSDictionary类的扩展,如下:

#import <Foundation/Foundation.h>

@interface NSDictionary (Safety)

- (id)safeObjectForKey:(id)aKey;

@end

以及实现文件:

#import "NSDictionary+Safety.h"

@implementation NSDictionary (Safety)

- (id)safeObjectForKey:(id)aKey {
  NSObject *object = self[aKey];

  if (object == [NSNull null]) {
    return nil;
  }

  return object;
}

@end

在你的代码中,不要使用[dictionary objectForKey:@"keyName"];,而应该使用

[dictionary safeObjectForKey:@"keyName"];

正如Tommy解释的那样,采用这种方法,您将向nil发送一个方法调用,这不会导致应用程序崩溃,但是您的对象将获得一个nil值。

希望这可以帮助您。


7
每当我尝试检查从字典中返回的对象是否为null时,我会这样做:
id obj = [myDictionary objectForKey:entityKeyName];
if (obj == [NSNull null]) {
    // do something 
}

然后在你的代码中,它将是这样的:

NSDictionary *result;
NSString *myImageURL = [result objectForKey:@"url"];
if (myImageURL == [NSNull null])
     myImageURL = @"";

在你的代码中,我会这样做。

另外,只是确认一下,NSDictionary的结果有被定义吗?在你的代码中,它没有被赋值到任何东西上。它只是被定义为一个你打算使用的名为results的变量。


你需要对任何NSString进行NSNull转换。 - lifemoveson

7
下面的答案对我有用: https://dev59.com/s3E85IYBdhLWcg3wbS1h#2784675
if ([dictionary objectForKey:key]) {
    // previously stored data for "key"
}

请注意,您可以使用以下方法获取字典中所有键的数组:

[dictionary allKeys]

这是最好的答案,如果字典中没有该键,则无需保留变量。在if语句中设置它。+1 - John Riselvato
这看起来应该可以工作,但实际上并没有。如果存在NSNull null,objectForKey仍然会返回true。 - quantumpotato
@quantumpotato,如果字典中不存在该键,则NSDictionary:objectForKey:返回nil,请参阅NSDictionary的类参考。尽管如此,我已经测试过了,似乎没有问题。 - Yunus Nedim Mehel
有一个变量可以避免重复使用 [dictionary objectForkey:key] 是很好的。dictionary[@"key"] 与 objectForKey 做的事情是一样的,对吗? - quantumpotato
@quantumpotato,是的,我同意。 - Yunus Nedim Mehel

4
如果一个键对应的对象不存在,NSDictionary 将返回 nil。而 NSNull 是一种实际的对象,因此是一种不同的东西。这就像记录有一个值和该值为空之间的区别,而不是记录是否有一个值。它还在于你以 C 指向对象的间接方式思考,而不仅仅是一个对象,因此从这个角度来看它并不完全符合语义。
在 Objective-C 中,你可以向 nil 发送任何消息,并保证结果为 nil(或 0)。因此,如果你的代码旨在确保你拥有一个安全的对象引用,就像在 C++ 中一样,那么你所做的是不必要的。例如:
object = [[Type alloc] init];

即使分配失败并返回nil,也始终明确安全。所有会发生的事情就是调用init不会做任何事情,对象最终将具有值nil,因为向nil发送init的结果也是nil

话虽如此,Bill和Emmanuel提供的答案应该是正确的。直接将结果与nil进行比较或隐式地将其与零进行比较。如果您后来遇到崩溃,我猜测是因为您期望myImageUrlmyImageNSString以外的类型(我注意到您在原始代码中使用了无类型的id),并向它们发送了它们无法响应的消息。


2
NSDictionary *result;
NSString *myImageURL = [result objectForKey:@"url"];
if (myImageURL == NULL)
    myImageURL = @"";

NSString *myImage = [result objectForKey:@"image"];
if (myImageURL == NULL)
    myImage = @"";

试试看它是否有效,而不是过度思考NULL类。


不对。我使用NSLog,得到了这个答案:result : { } 然后就出错了。还不知道出了什么问题? - lifemoveson
你在 myImageURL 上做了 NSLog 吗?在检查 null 前吗?我建议检查一下前后。 NSLog(@"result: %@", [result objectForKey:@"url"]); NSLog(@"myImageURL: %@", myImageURL); - Bill Burgess

2
这是另一种选择:
if (![result objectForKey:@"image"])
    {
        NSLog(@"doesn't exist");
    }
    if ([result objectForKey:@"image"])
    {
        NSLog(@"exist");
    }

1

好的,这是实际答案,@Iomec几乎已经说对了

UIImage *myImage = ([result objectForKey:@"image"] != [NSNull null] ? [result objectForKey:@"image"] : nil);

这是实际的正确答案,因为它为null,当你说myImage = [receivedObject...];时,如果myImage = nil,则实际上将null值(nil)转换为一个类,这是一个例外,如果不是运行时错误。

您应该: 1)测试NSNull null值 2)如果不是nil,则分配

如果您的代码尚未出现故障,则在某一天有8个应用程序在后台运行时,它将在生产中出现问题。


1

对我来说那并没有起作用,我是这样解决的

id myImageURL = [result objectForKey:@"url"];
if ([myImageURL isKindOfClass:[NSNull class]])  
    myImageURL = @"";

0
当您在可空字典中调用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;

}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接