Как разрешить NSMutableDictionary принимать значения 'nil'?

У меня есть это утверждение:

 [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"];
 Miek12 июн. 2014 г., 20:52
Это похоже на хорошее решение для меня. @ "" - это хороший способ сохранить заполнители для ключей, когда нет действительного значения, в противном случае у вас может возникнуть та же проблема при доступе к значениям для ключей позже.
 gnasher72918 апр. 2015 г., 21:43
Как ярлык: custData [@ "email"] = [rs stringForColumnIndex: 2]?: @ "";

Ответы на вопрос(3)

NSDictionary значение, которое может или не может быть установлено еще изNSUserDefaults.

То, что я сделал, было обернуть значения вstringwithFormat вызов. Оба значения еще не установлены, поэтому начинайте с нуля. Когда я бегу безstringwithFormat вызов приложения вылетает. Так я и сделал, и в моей ситуации сработало.

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

return userDetails;
}
 Chris Nolet15 мая 2016 г., 10:09
Я считаю, что это просто транспонированиеnil значения в пустую строку. Вы также можете сделатьvalue ?: @"" (сокращение отvalue ? value : @"".
Решение Вопроса

nil объект называетсяNSNull созданный специально для представленияnils в ситуациях, когда "обычный"nil не допускается. Если вы замените свойnil с[NSNull null] объект,NSDictionary примет их. Вам нужно будет проверить наNSNull на выходе, хотя.

Обратите внимание, что это важно только в том случае, если необходимо различать не заданное значение и заданное значениеnil. Если ваш код таков, что он может Интерпретировать пропущенное значение какnil, вам не нужно использоватьNSNull вообще

 user52975826 авг. 2013 г., 06:21
@ spokane-dude Вы также должны взглянуть на другой ответ, этона самом дел отвечает на ваш вопрос.
 dasblinkenlight01 июн. 2012 г., 22:29
@ spokane-dude Нет, к сожалению, нет настроек, которые позволили бы вам хранитьnil в коллекциях какао. Если вы используете условный оператор, есть расширение, которое позволяет несколько сократить код (см.эта ссылк).
 SpokaneDude01 июн. 2012 г., 22:37
Это то, что я наконец-то сделал (см. Обновленный вопрос выше), и это работает (по крайней мере, предотвращает сбой приложения; я проверю на стороне метода наличие пустого ключа. Спасибо за ваше время.
 SpokaneDude01 июн. 2012 г., 22:25
Я устанавливаю значения в NSMutableDictionary, чтобы я мог передать массив данных методу (Objective-c). Таким образом, метод может обрабатывать ноль, но, очевидно, словарь не может. Так что я не могу установить параметр, позволяющий использовать «ноль» ключи, а? Вероятно, придется использовать условный оператор?

и в большинстве случаев вы хотите преобразовать нулевые значения в[NSNull null] или просто опустить их из словаря. Иногда (очень редко), тем не менее, удобно разрешать значения nil, и в этих случаях вы можете использовать CFMutableDictionary с пользовательскими обратными вызовами.

Если вы идете по этому пути, я рекомендую использовать CoreFoundation API для всех обращений, например,CFDictionarySetValue а такжеCFDictionaryGetValue.

Однако, если вы знаете, что делаете, вы можете использовать бесплатный мост и преобразовать этот CFMutableDictionary в NSMutableDictionary или NSDictionary. Это может быть полезно, если у вас есть несколько помощников, которые принимают NSDictionary, и вы хотите использовать их в своем модифицированном словаре с поддержкой nil. (Конечно, убедитесь, что помощники не удивлены нулевыми значениями.)

Если вы используете мост, обратите внимание:

1) Установщик NSMutableDictionary выдает ошибки в значениях nil перед установкой моста, поэтому вам нужно использовать CFDictionarySetValue для установки значений, которые потенциально могут быть nil.

2) технически, мы нарушаем контракт NSMutableDictionary здесь, и вещи могут сломаться (например, в будущих обновлениях ОС)

3) большая часть кода будет очень удивлена, обнаружив нулевые значения в словаре; Вы должны передавать только соединенные по буквам словарей в код, которым вы управляет

Видеть смешной пост о бесплатном мостовом соединении для объяснения того, почему мостовой 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;
}

outputs:

dictionary[foo] = bar
dictionary[foo] = bar
dictionary[boz] = (null)
dictionary = {
    boz = (null);
    foo = bar;
}
(dictionary isEqualTo: dictionary) = 1
 Carl Lindberg20 апр. 2015 г., 09:35
CFEqual завершится с параметрами NULL; ваш пример может сработать, если внешний код проверяет равенство указателей перед вызовом этой функции, но если вы создадите копию словаря выше, но установите для ключа boz правильное значение, то сравните два словаря, я полагаю, что это приведет к сбою вместо возвращая ложь. Я думаю, вам нужна нулевая безопасная оболочка для CFEqual, чтобы присвоить свойству ValueCallBacks.

Ваш ответ на вопрос