1

I have dictionary of user information, that is getting filled from web service. There are some fields that content is private so it contains NULL. How do I convert value to an empty string wherever there is the value null as in dictionary below:

{
"about_me" = "<null>";
"contact_number" = 123456798798;
"display_name" = "err";
followers = 0;
following = 4;
gender = "-";
posts = 0;
"user_id" = 18;
username = charge;
website = "<null>";
}
Jonathan.
  • 53,997
  • 54
  • 186
  • 290
Chirag Hirpara
  • 101
  • 2
  • 14

6 Answers6

3

The simplest way to do this is to loop through a mutable copy of the dictionary and if the value is
null set the value to the value you want.

NSMutableDictionary *mutableDict = [dict mutableCopy];
for (NSString *key in [dict allKeys]) {
    if ([dict[key] isEqual:[NSNull null]]) {
        mutableDict[key] = @"";//or [NSNull null] or whatever value you want to change it to
    }
}
dict = [mutableDict copy];

If the value in the dictionary is actually "<null>", replace the conditional with [dict[key] isEqualToString:@"<null>"]

(assuming you're using ARC, otherwise you need to release the copy'd dictionaries)

Jonathan.
  • 53,997
  • 54
  • 186
  • 290
  • as @{ @"website":[NSNull null] } prints { website = "";} I'd assume it isn't a string. – vikingosegundo Jul 16 '14 at 08:46
  • NSLog is not made for converting NSNull in a valid JSON value. If you print [NSNull null], "" is printed. However, if you serialize it with NSJSONSerialization, the value is correctly converted to json null – LombaX Jul 16 '14 at 08:53
  • I am just saying that I thing there is a NSNull in the dictionary. – vikingosegundo Jul 16 '14 at 09:00
3

A more advanced solution :

@interface NSObject (NULLValidation)
- (BOOL)isNull ;
@end

@implementation NSObject (NULLValidation)

- (BOOL)isNull{
    if (!self) return YES;
    else if (self == [NSNull null]) return YES;
    else if ([self isKindOfClass:[NSString class]]) {
        return ([((NSString *)self)isEqualToString : @""]
                || [((NSString *)self)isEqualToString : @"null"]
                || [((NSString *)self)isEqualToString : @"<null>"]
                || [((NSString *)self)isEqualToString : @"(null)"]
                );
    }
    return NO;

}
@end


@interface NSDictionary (NullReplacement)
- (NSDictionary *) dictionaryByReplacingNullsWithString:(NSString*)string;
@end

@implementation NSDictionary (NullReplacement)

- (NSDictionary *) dictionaryByReplacingNullsWithString:(NSString*)string {
     NSMutableDictionary *replaced = [NSMutableDictionary dictionaryWithDictionary: self];

     NSString *blank = string;

    [self enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        if ([obj isNull]) {
            [replaced setObject:blank forKey: key];
        }
        else if ([obj isKindOfClass: [NSDictionary class]]) {
            [replaced setObject: [(NSDictionary *) obj dictionaryByReplacingNullsWithString:string] forKey: key];
        }
    }];

    return replaced ;
}
@end
Meseery
  • 1,845
  • 2
  • 22
  • 19
  • -1 because -isNull has several problems. First, you fail to use polymorphism. You shouldn't have a single method in the root class that tests if the instance is of a subclass. Just put the desired behavior in the subclass. For NSNull, just return YES and for NSString return the results of the string comparisons. Second, -[NSObject isNull] should never be called if the reference is nil. Not only should the runtime ignore it, but array elements and dictionary values default to throwing an exception. That's why NSNull exists, as a workaround. – Huperniketes Nov 23 '16 at 20:06
1

First of all, "<null>" is not a valid JSON null value.
Written it that way, it is simply a string containing the word <null>

In JSON, null is written in this way.

{ "value": null }

So, if you can't update your web service to return valid json, I suggest you to do a replace on the JSON string in the first instance. Then when you have valid JSON null values, simply handle it with NSJSONSerialization

NSString *json = @"{ \"value\": null }";
NSError *error = nil;
id jsonObject = [NSJSONSerialization JSONObjectWithData:[json dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:&error];

NSLog(@"%@", jsonObject);

This prints

2014-07-16 10:31:36.737 MacUtilities[30760:303] {
    value = "<null>";
}

And debugging the class of value

po [[jsonObject objectForKey:@"value"] class];
NSNull

This because NSJSONSerialization handles null correctly, turning it into an NSNull instance

LombaX
  • 17,265
  • 5
  • 52
  • 77
  • 1
    There is a lot of downvoting in this question with no explanation. It's not clear why anyone should contribute anything to this site sometimes... – trojanfoe Jul 16 '14 at 09:03
1

Swift 3.0/4.0 Solution

Following is the solution, when JSON have sub-dictionaries. This will go-through all the dictionaries, sub-dictionaries of JSON and remove NULL(NSNull) key-value pair from the JSON.

extension Dictionary {

    func removeNull() -> Dictionary {
        let mainDict = NSMutableDictionary.init(dictionary: self)
        for _dict in mainDict {
            if _dict.value is NSNull {
                mainDict.removeObject(forKey: _dict.key)
            }
            if _dict.value is NSDictionary {
                let test1 = (_dict.value as! NSDictionary).filter({ $0.value is NSNull }).map({ $0 })
                let mutableDict = NSMutableDictionary.init(dictionary: _dict.value as! NSDictionary)
                for test in test1 {
                    mutableDict.removeObject(forKey: test.key)
                }
                mainDict.removeObject(forKey: _dict.key)
                mainDict.setValue(mutableDict, forKey: _dict.key as? String ?? "")
            }
            if _dict.value is NSArray {
                let mutableArray = NSMutableArray.init(object: _dict.value)
                for (index,element) in mutableArray.enumerated() where element is NSDictionary {
                    let test1 = (element as! NSDictionary).filter({ $0.value is NSNull }).map({ $0 })
                    let mutableDict = NSMutableDictionary.init(dictionary: element as! NSDictionary)
                    for test in test1 {
                        mutableDict.removeObject(forKey: test.key)
                    }
                    mutableArray.replaceObject(at: index, with: mutableDict)
                }
                mainDict.removeObject(forKey: _dict.key)
                mainDict.setValue(mutableArray, forKey: _dict.key as? String ?? "")
            }
        }
        return mainDict as! Dictionary<Key, Value>
    }
 }
Rashesh Bosamiya
  • 609
  • 1
  • 9
  • 13
0

You have an Dictionary not an array. Maybe you have an array of dictionaries. Enumerate through the array and do the null check for each dictionary's Key Value pairs.

You have a parsed NSDictionary probably from a JSON repsonse. Probably the JSON contains null values, and the JSON parser you're using turns null into [NSNull null], and it doesn't work if you're trying to compare a string against that NSNull. In this case, try this:

if ([yourDictionary objectForKey:@"website"]== [NSNull null]) {
    // handle here
}
Rukshan
  • 7,902
  • 6
  • 43
  • 61
  • 3
    FYI: the `[NSNull null]` is not the same as the `@""` on any level; and those kind of comparison is not really valid on any level. – holex Jul 16 '14 at 08:19
  • 2
    FYI: @{ @"website":[NSNull null] } prints as { website = "";} @holex – vikingosegundo Jul 16 '14 at 08:45
  • @holex , FYI: @"" isn't a string, that's how it [NSNull null] gets printed in console as 'vikingosegundo' explained. Accepted answer proves that. – Rukshan Apr 29 '15 at 04:04
0

In swift-4 rather then remove you can replace null values to empty string by using following method

func removeNullFromDict (dict : NSMutableDictionary) -> NSMutableDictionary
{
    let dic = dict;

    for (key, value) in dict {

        let val : NSObject = value as! NSObject;
        if(val.isEqual(NSNull()))
        {
            dic.setValue("", forKey: (key as? String)!)
        }
        else
        {
            dic.setValue(value, forKey: key as! String)
        }

    }

    return dic;
}

and before giving dict to any method call function in below way

let newdict = self.removeNullFromDict(dict: dict);
Anita Nagori
  • 707
  • 1
  • 7
  • 21