Это невозможно с чистым NSMutableDictionary, и в большинстве случаев вы хотите преобразовать значения nil в [NSNull null]
или просто опустить их из словаря. Иногда (очень редко), однако, удобно указывать значения nil, и в этих случаях вы можете использовать CFMutableDictionary с пользовательскими обратными вызовами.
Если вы идете этим путем, я рекомендую вам использовать API CoreFoundation для всех видов доступа, например. CFDictionarySetValue
и CFDictionaryGetValue
.
Однако, если вы знаете, что делаете, вы можете использовать бесплатный мостик и отбросить этот CFMutableDictionary в NSMutableDictionary или NSDictionary. Это может быть полезно, если у вас есть куча помощников, которые принимают NSDictionary, и вы хотите использовать их в своем модифицированном словаре с поддержкой nil. (Конечно, убедитесь, что помощники не удивлены нулевыми значениями.)
Если вы делаете мостики, обратите внимание, что:
1) NSMutableDictionary сеттер вызывает ошибки на нулевых значениях перед тем преодоление, так что вам нужно использовать CFDictionarySetValue для установки значений, которые потенциально равны нулю.
2) технически, мы нарушив договор о NSMutableDictionary здесь, и вещи могут нарушить (например, в будущих обновлениях ОС)
3) много кода будет очень удивлен, чтобы найти нулевые значения в словаре ; вы должны передавать только мостовые франкенд-словари в код, который вы контролируете
См. ridiculousfish's post on toll-free bridging для объяснения причин, по которым мостовой 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
Это выглядит как хорошее решение для меня. @ "- это хороший способ сохранить заполнители для ключей, когда нет допустимого значения, иначе вы можете иметь такую же проблему, когда позже будете получать значения для ключей. – Miek
В качестве ярлыка: custData [@ "email"] = [rs stringForColumnIndex: 2]?: @ ""; – gnasher729