Objective c 如何允许NSMutableDictionary接受';无';价值观

Objective c 如何允许NSMutableDictionary接受';无';价值观,objective-c,Objective C,我有以下声明: [custData setObject: [rs stringForColumnIndex:2] forKey: @"email"]; 其中,从SQLite3 d/b获取的[rs stringForColumnIndex:2]的值为nil。应用程序崩溃,出现以下错误: NSCFDictionary setObject:forKey:]: attempt to insert nil value (key: email)' 有没有办法防止这种情况?(如NSMutableDic

我有以下声明:

 [custData setObject: [rs stringForColumnIndex:2]  forKey: @"email"];
其中,从SQLite3 d/b获取的
[rs stringForColumnIndex:2]
的值为
nil
。应用程序崩溃,出现以下错误:

NSCFDictionary setObject:forKey:]: attempt to insert nil value (key: email)'
有没有办法防止这种情况?(如
NSMutableDictionary
?)的设置)

更新:这是我最后做的:

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

有一个名为非
nil
的对象,该对象专门用于在不接受“普通”
nil
的情况下表示
nil
s。如果将
nil
s替换为
[NSNull]
对象,
NSDictionary
将接受它们。不过,您需要在退出时检查
NSNull


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

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

如果您这样做,我建议您对所有访问使用CoreFoundation API,例如
CFDictionarySetValue
CFDictionaryGetValue

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

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

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

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

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

有关桥接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;
}

我需要将
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;
}

我正在NSMutableDictionary中设置值,以便将数据数组传递给方法(Objective-c)。因此,该方法可以处理nil,但字典显然不能。所以我不能设置为允许“零”键,是吗?可能必须使用条件运算符?@spokane dude不,不幸的是,没有设置允许您在cocoa集合中存储
nil
。如果您使用条件运算符,那么有一个扩展可以让您稍微缩短代码(请参阅)。这就是我最后所做的(请参阅上面更新的问题),它是有效的(至少可以防止应用程序崩溃;我会在方法一侧检查是否有空键。感谢您抽出时间。@斯波坎·杜德您还应该看看另一个答案,它实际上回答了您的问题。这对我来说是一个很好的解决方案。@“”是在没有有效值时维护键的占位符的好方法,否则以后访问键的值时可能会遇到同样的问题。作为快捷方式:custData[@“email”]=[rs stringForColumnIndex:2]?:@“”;CFEqual将使用NULL参数崩溃;如果外部代码在调用该函数之前检查指针相等性,则您的示例可能会起作用,但是如果您要创建上述字典的副本,但将boz键设置为有效值,然后比较这两个字典,我相信它将崩溃而不是返回false。您需要一个NULL安全包装器我认为,对于CFEqual分配给ValueCallBacks属性,我认为这只是将
nil
值转换为空字符串。您还可以执行
value?:@“
(这是
value?value:@”的缩写)。
-(NSDictionary*)userDetailsDict{
NSDictionary* userDetails = @{
                              @"userLine":[NSString stringWithFormat:@"%@",[[NSUserDefaults standardUserDefaults]stringForKey:kSelectedLine] ],
                              @"userDepot":[NSString stringWithFormat:@"%@",[[NSUserDefaults standardUserDefaults]stringForKey:@"kSelected Duty Book"]]
                              };

return userDetails;
}