iOS: Why can't I set nil to NSDictionary value?

40,525

Solution 1

It wants an actual object... use NSNull

[NSNull null];

Solution 2

You can set a nil value using setValue:forKey but it removes the key.

If you want to be able to set a key to nil you could use setValue:forKey: which will remove the key if you set it to nil (quote from documentation below). Note the Value instead of Object.

setValue:forKey:

Adds a given key-value pair to the dictionary.

...
Discussion

This method adds value and key to the dictionary using setObject:forKey:, unless value is nil in which case the method instead attempts to remove key using removeObjectForKey:.

When you later try and get the object using objectForKey: for the key that you removed by setting it to nil you will get nil back (quote from documentation below).

Return value:

The value associated with aKey, or nil if no value is associated with aKey.

Note: The key will not actually be present in the dictionary so it won't be obtained using allKeys; or be enumerated over.

Solution 3

You can set nil object in this way:

NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];

dictionary[@“key”] = nil;

Have you noticed it?

NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];

/* this statement is safe to execute    */

dictionary[@“key”] = nil;

/* but this statement will crash application    */

[dictionary setObject:nil forKey:@"key"];

Solution 4

When using this method:

func setObject(_ anObject: Any, forKey aKey: NSCopying)

Parameters (according to Apple doc's):

anObject:

Raises an invalidArgumentException if anObject is nil. If you need to represent a nil value in the dictionary, use NSNull .

aKey

Raises an invalidArgumentException if aKey is nil.

Share:
40,525

Related videos on Youtube

Paresh Masani
Author by

Paresh Masani

Updated on July 09, 2022

Comments

  • Paresh Masani
    Paresh Masani almost 2 years

    This might be very basic question but I was wondering why can't I assign nil as NSDictionary value? I have following statement many places in my code. If [q objectForKey:@"text"] is nil then App is crashing.

    NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:2];
    [dict setObject:[q objectForKey:@"text"] forKey:@"text"];
    

    I have to check everywhere for the nil before assigning it to dictionary. Is this the only correct way of doing? Am I missing something obvious?

    if([q objectForKey:@"text"] != nil)
        [dict setObject:[q objectForKey:@"text"] forKey:@"text"];
    else
        [dict setObject:@"" forKey:@"text"];
    
  • Paresh Masani
    Paresh Masani almost 12 years
    This looks great. When I set NSNull, the condition if([q objectForKey:@"text"] == nil) will be true or do I have to use if([q objectForKey:@"text"] == NSNull)? Thanks.
  • Paresh Masani
    Paresh Masani almost 12 years
    I know that but a I had to do this to set default value for the key! Can you just create key without assigning value?
  • David Rönnqvist
    David Rönnqvist almost 12 years
    @AppleDeveloper Please explain what you would gain by having a key without a value...
  • Kunal Balani
    Kunal Balani almost 12 years
    The short ans is no and long ans is Noooooooooooooo.
  • Paresh Masani
    Paresh Masani almost 12 years
    Hi David, Thanks for the useful info but I read on Apple documents that you use setValue only for KVO and for normal key-value pair, you should always use setObject! Isn't that true?
  • Peter Pajchl
    Peter Pajchl almost 12 years
    @AppleDeveloper it won't be true, you will have to check against [NSNull null]
  • Paresh Masani
    Paresh Masani almost 12 years
    Thanks @peter so I will need to use two different conditions? if([q objectForKey:@"text"] == nil) to check if key is exists or not and if([q objectForKey:@"text"] == [NSNull null]) to check if key has null value?
  • David Rönnqvist
    David Rönnqvist almost 12 years
    @AppleDeveloper As far as I know, dictionaries have their own setValue implementation. The NSMutableDictionary documentation (linked in my answer) says nothing about not using it: "setValue:forKey: Adds a given key-value pair to the dictionary. ... Discussion This method adds value and key to the dictionary using setObject:forKey:, unless value is nil in which case the method instead attempts to remove key using removeObjectForKey:."
  • Paresh Masani
    Paresh Masani almost 12 years
    @DavidRönnqvist sorry I know it's not possible but I was little sarcastic there! I am building 100s of key-value pair where some of them have values and some are missing and will be filled by user. I am generating dynamic UI controls so still if particular key doesn't have an answer/default value,I need to store that key for future reference and assign the value later on.
  • Kunal Balani
    Kunal Balani almost 12 years
    @AppleDeveloper we all hinting you that you have a wrong design . Insert key value when you have both (this will save you memory too) . I dont know what your context is but you can always have a better solution than inserting nil value .
  • Paresh Masani
    Paresh Masani almost 12 years
    @KunalBalani I generate UI dynamically, each key has, particular control associated with it. When control value changes, I need to set the value to associated key and not any other so I have to preserve it and attach with the control. I know I am doing it correct but anyway I would check if I can avoid using nil. Thanks.
  • Paresh Masani
    Paresh Masani almost 12 years
    ....and just for your information I haven't been assigning nil but @"" and it's the way whole ASIHTTPRequest framework designed and implemented.
  • Peter Pajchl
    Peter Pajchl over 11 years
    @AppleDeveloper since you can't store nil in NSDictionary, checking for it is obsolete as it can't ever happen. So, no, don't check for nil, only check for [NSNull null].
  • fishinear
    fishinear over 11 years
    I would like to support AppleDeveloper here. Storing nil in a dictionary is a perfectly sensible thing to do in many situations (like the one AppleDeveloper mentions), and not necessarily a wrong design. And there is no reason at all for Apple not to support it.
  • eremzeit
    eremzeit almost 10 years
    I disagree about the assumption that wanting to store nil implies bad programming. In many scenarios, there is an important difference between knowing that a key is nil and knowing nothing at all. Why not be able to model this case? Broadly speaking, broad statements are hardly ever true ;)
  • Kunal Balani
    Kunal Balani almost 10 years
    @eremzeit I agree that broad statements are not true. How about you come up with an example which requires to store nil and I will tell you a way to solve the same problem without it.
  • user3378170
    user3378170 about 9 years
    Thats why Apple developed Swift. A collection or array can contain values of a specific type. Since swift arrays do not care about the specific type, the values can be of a optional type. For example your swift array can contain values of type String? (optional String). For every index, there can be value of type String or no value at all (nil) which basically means the value is not available in Swift.
  • Benjohn
    Benjohn almost 9 years
    A significant restriction of this approach is that setValue:withKey: expects a string key. It's not entirely clear that using other types is safe, and the compiler issues a warning for it. I think I'd avoid it, personally. I think a category on NSMutableDictionary providing setOrClearObject:forKey: would be a safer approach.
  • Vyachaslav Gerchicov
    Vyachaslav Gerchicov almost 9 years
    objectForKey: returns object. So you need a voting down because you don't simply write ![q objectForKey:@"text"]
  • Abhi Beckert
    Abhi Beckert over 3 years
    @PeterPajchl it will be nil if the key is doesn't have a value.