使用纯 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 传递给您控制的代码
有关为什么桥接的 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