我有这样的声明:
[custData setObject: [rs stringForColumnIndex:2] forKey: @"email"];
Run Code Online (Sandbox Code Playgroud)
其中[rs stringForColumnIndex:2]从SQLite3的d/b中获得具有值nil.该应用程序崩溃给我错误:
NSCFDictionary setObject:forKey:]: attempt to insert nil value (key: email)'
Run Code Online (Sandbox Code Playgroud)
有办法防止这种情况吗?(比如设置NSMutableDictionary?)
更新:这是我最终做的:
[custData setObject: ([rs stringForColumnIndex:2] != nil? [rs stringForColumnIndex:2]:@"") forKey: @"email"];
Run Code Online (Sandbox Code Playgroud)
使用纯NSMutableDictionary是不可能的,并且在大多数情况下,您希望将nil值转换为[NSNull null]或仅从字典中省略它们.但是,有时(非常少),允许nil值很方便,在这种情况下,您可以将CFMutableDictionary与自定义回调一起使用.
如果你这样做,我建议你使用CoreFoundation API进行所有访问,例如CFDictionarySetValue和CFDictionaryGetValue.
但是,如果您知道自己在做什么,则可以使用免费桥接并将CFMutableDictionary强制转换为NSMutableDictionary或NSDictionary.如果您有一堆接受NSDictionary的帮助程序,并且您希望在修改后的nil字典上使用它们,这可能很有用.(当然,确保帮助者不会对nil值感到惊讶.)
如果您进行桥接,请注意:
1)NSMutableDictionary setter在桥接之前引发nil值的错误,因此您需要使用CFDictionarySetValue来设置可能为nil的值.
2)从技术上讲,我们在这里违反了NSMutableDictionary的合同,事情可能会中断(例如在未来的操作系统更新中)
3)很多代码在字典中找到nil值会非常惊讶; 你应该只将桥接的frankendictionaries传递给你控制的代码
请参阅ridiculousfish关于免费桥接的帖子,以解释为什么桥接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;
}
Run Code Online (Sandbox Code Playgroud)
输出:
dictionary[foo] = bar
dictionary[foo] = bar
dictionary[boz] = (null)
dictionary = {
boz = (null);
foo = bar;
}
(dictionary isEqualTo: dictionary) = 1
Run Code Online (Sandbox Code Playgroud)