20

我有这样的声明:

 [custData setObject: [rs stringForColumnIndex:2]  forKey: @"email"];

其中[rs stringForColumnIndex:2]从 SQLite3 d/b 获得的值为nil. 该应用程序崩溃给我错误:

NSCFDictionary setObject:forKey:]: attempt to insert nil value (key: email)'

有没有办法防止这种情况?(比如设置NSMutableDictionary?)

更新:这就是我最终所做的:

[custData setObject: ([rs stringForColumnIndex:2] != nil? [rs stringForColumnIndex:2]:@"") forKey: @"email"];
4

3 回答 3

38

有一个非nil对象称为NSNull,它专门用于在“普通”不可接受nil的情况下表示 s 。nil如果你用对象替换你nil的 s ,就会拿走它们。不过,您需要在外出时检查。[NSNull null]NSDictionaryNSNull

请注意,仅当您必须区分未设置的值和设置为的值时,这才重要nil。如果您的代码可以将缺失值解释nil,则根本不需要使用NSNull

于 2012-06-01T20:16:42.467 回答
5

使用纯 NSMutableDictionary 是不可能的,并且在大多数情况下,您希望将 nil 值转换为[NSNull null]或只是从字典中省略它们。但是,有时(很少)允许 nil 值很方便,在这种情况下,您可以使用 CFMutableDictionary 和自定义回调。

如果您采用这种方式,我建议您使用 CoreFoundation API 进行所有访问,例如CFDictionarySetValueCFDictionaryGetValue.

但是,如果您知道自己在做什么,则可以使用免费桥接并将 CFMutableDictionary 转换为 NSMutableDictionary 或 NSDictionary。如果您有一堆接受 NSDictionary 的助手,并且您想在修改后的支持 nil 的字典上使用它们,这可能会很有用。(当然,确保助手不会对 nil 值感到惊讶。)

如果您进行桥接,请注意:

1) NSMutableDictionary setter 在桥接之前会在 nil 值上引发错误,因此您需要使用 CFDictionarySetValue 来设置可能为 nil 的值。

2) 从技术上讲,我们在这里违反了 NSMutableDictionary 的合同,并且事情可能会中断(例如,在未来的操作系统更新中)

3) 很多代码在字典中找到 nil 值会非常惊讶;您应该只将桥接的 frankendictionaries 传递给您控制的代码

有关为什么桥接的 CFDictionary 与 NSDictionary 的行为不同的解释,请参阅荒谬的鱼关于免费桥接的帖子。

例子:

#import <Foundation/Foundation.h>

const void *NullSafeRetain(CFAllocatorRef allocator, const void *value) {
    return value ? CFRetain(value) : NULL;
}
void NullSafeRelease(CFAllocatorRef allocator, const void *value) {
    if (value)
        CFRelease(value);
}
const CFDictionaryValueCallBacks kDictionaryValueCallBacksAllowingNULL = {
    .version = 0,
    .retain = NullSafeRetain,
    .release = NullSafeRelease,
    .copyDescription = CFCopyDescription,
    .equal = CFEqual,
};

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        CFMutableDictionaryRef cfdictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kDictionaryValueCallBacksAllowingNULL);
        CFDictionarySetValue(cfdictionary, @"foo", @"bar");
        CFDictionarySetValue(cfdictionary, @"boz", nil);

        NSMutableDictionary *dictionary = CFBridgingRelease(cfdictionary);
        NSLog(@"dictionary[foo] = %@", dictionary[@"foo"]);
        NSLog(@"dictionary[foo] = %@", dictionary[[@"fo" stringByAppendingString:@"o"]]);
        NSLog(@"dictionary[boz] = %@", dictionary[@"boz"]);
        NSLog(@"dictionary = %@", dictionary);
        NSLog(@"(dictionary isEqualTo: dictionary) = %d", [dictionary isEqualToDictionary:dictionary]);
    }
    return 0;
}

输出:

dictionary[foo] = bar
dictionary[foo] = bar
dictionary[boz] = (null)
dictionary = {
    boz = (null);
    foo = bar;
}
(dictionary isEqualTo: dictionary) = 1
于 2013-07-19T05:00:47.710 回答
0

我需要将一个NSDictionary值设置为可能或尚未设置的值NSUserDefaults

我所做的是将值包装在一个stringwithFormat调用中。这两个值都还没有设置,所以从 null 开始。当我在没有stringwithFormat调用的情况下运行时,应用程序崩溃。所以我这样做了,在我的情况下工作。

-(NSDictionary*)userDetailsDict{
NSDictionary* userDetails = @{
                              @"userLine":[NSString stringWithFormat:@"%@",[[NSUserDefaults standardUserDefaults]stringForKey:kSelectedLine] ],
                              @"userDepot":[NSString stringWithFormat:@"%@",[[NSUserDefaults standardUserDefaults]stringForKey:@"kSelected Duty Book"]]
                              };

return userDetails;
}
于 2015-04-07T09:14:42.667 回答