Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSDictionaray dictionaryWithObjectsAndKeys adding NULL value

I want to create a NSDictionary with +[NSDictionary dictionaryWithObjectsAndKeys:]. One of my keys has a string but the string can sometimes be nil. If the string is nil, any other value key pairs I put afterward will be ignored because the list is prematurely terminated. What is the standard way to deal with the possibility that there might be a value with nil in a NSDictionary?

like image 610
prostock Avatar asked Jun 23 '11 21:06

prostock


People also ask

How do I know if NSDictionary is empty?

To check if a dictionary is empty, you can either check if the size of the dictionary is zero or use the isEmpty function. The type of keys array is same as that of keyType , and the type of values array is same as that of valueType .

Does NSDictionary retain objects?

An NSDictionary will retain it's objects, and copy it's keys. Here are some effects this has had on code I've worked on. Sometimes you get the same object you put in, sometimes not. Immutable objects are optimized to return themselves as a copy .

What is NSDictionary in Swift?

An object representing a dynamic collection of key-value pairs, for use instead of a Dictionary variable in cases that require reference semantics.


2 Answers

You need to check if the string is null. If it is, add [NSNull null] instead of your string.

like image 147
VenoMKO Avatar answered Nov 08 '22 11:11

VenoMKO


Creating NSDictionary objects can be combersome if you have many objects, that if they are nil, should not be included in the dictionary.

To me NSNull is as big a problem as it is the solution. When creating NSDictionary objects for usage in other objects, you can go two ways when dealing with nil values. Either you add NSNull objects to your dictionary - and then check for NSNull values when reading the values. This makes pretty code at the point of creation, but it becomes messy when reading out the values. Ex. should you check all keys in the dictionary, or are some garanteed to be not nil? And if an NSNull value is not filtered out it is bound to make exceptions when trying to send the object messages.

The second way is to just not add NSNull values to the dictionary. This is convinient when reading the NSDictionary, as the [someDictionary objectForKey:someKey] simply returns nil when the key is not set. This approach makes it pretty this easy when reading the values, but it really is bound to be messy code on creation. Ex. Creating a NSMutableDictionary, checking for nil before adding values, and finally returning an immutable copy?

Solution

To me the solution has been to create two categories, which in essense makes it easy for both the creating and the reading ends.

When creating the NSDictionary, you simply wrap you possible-nil values like this

[NSDictionary dictionaryWithObjectsAndKeysIngoringNull:
 [NSNull nullWhenNil:val1], @"value1",
 [NSNull nullWhenNil:val2], @"value2",
 ...
 nil];

This code is almost as simple as approach number one, but it makes it substantially easier when reading out the values.

The categories is as follows (works in both ARC enabled and non-ARC code):

NSDictionary addition:

@implementation NSDictionary (NullAddition)

+ (id)dictionaryWithObjectsAndKeysIngnoringNull:(id)firstObject, ... {

    NSMutableArray* objects = [NSMutableArray array];
    NSMutableArray* keys = [NSMutableArray array];

    va_list args;
    va_start(args, firstObject);

    for (id object = firstObject; object; object = va_arg(args, id)) {

        id key = va_arg(args, id);

        if (!key)
            break;

        if (![object isKindOfClass:[NSNull class]]) {
            [objects addObject:object];
            [keys addObject:key];
        }

    }

    va_end(args);

    return [self dictionaryWithObjects:objects forKeys:keys];

}

@end

NSNull addition

@implementation NSNull (NullAddition)

+ (id)nullWhenNil:(id)obj {

    return (obj ? obj : [self null]);

}

@end

Good luck!

like image 6
Trenskow Avatar answered Nov 08 '22 10:11

Trenskow