Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSDictionary fast KVC with nil values

Not sure if I named the question correctly but here goes:

Lets say I have a JSON response being returned from an API. The JSON gets parsed using SBJson which works flawlessly. An example of JSON:

{
    "value": 15199,          //this field is required
    "value_str": "$1.5k",    //this field is required
    "change": 33             //this field is optional
}

Now this gets parsed in a neat little NSDictionary from which I can read. So far I had it like so:

//lets assume that "dict" is the parsed JSON using SBJSON
NSDictionary *number = @{@"value_str": [dict objectForKey:@"value_str"]}; //this works
number = @{@"value_str": [dict objectForKey:@"value_str"], @"change": [dict objectForKey:@"change"]}; //this crashes if there was no "change" in JSON

So the crash occurs because I'm trying to set a nil value as an object to a NSDictionary which isn't allowed. This would work if the change field was always there though. How to fix this?
Do I really have to do it like:

NSDictionary *number = [NSDictionary dictionary];
[number setValue:[dict objectForKey:@"value_str"] forKey:@"value_str"];
[number setValue:[dict objectForKey:@"change"] forKey:@"change"];

and so on for every key-value pair in the dict? This is much more slower and painful to write. There has to be a better way, right? Please? :)

Oh and if I set the setValue ForKey and then query like objectForKey will I get the object (or value) which I set with setValue ForKey?

EDIT: I got an idea but I am not sure how to implement it efficiently. Instead of checking for every key here and so on why not subclass NSDictionary and override the @{} constructor which is dictionaryWithObjectsAndKeys I think. I am familiar with compiler va_lists but I do not have enough knowledge to implement such a constructor efficiently. If someone would do this it would be awesome. The whole idea is to check values in that constructor method and if the object is nil just skip it. How's that? Can someone make it tick or is it a bad idea?
EDIT2: Found out that subclassing is a bad idea :) used solution provided in the comments.

like image 773
Majster Avatar asked Feb 26 '26 02:02

Majster


1 Answers

About first question I think the best deal is to check value every time, or to make a copy of dictionary.

About second question:

objectForKey: accepts any object as a key, not just strings. The only requirement is that the key support the NSCopying protocol.

Another difference is that if you give a nil value to setValue:forKey:, it removes the key from the dictionary if it exists, otherwise does nothing. But if you give a nil value to setObject:forKey:, it raises an exception.

When you do valueForKey: you need to give it an NSString, whereas objectForKey: can take any NSObject subclass as a key. This is because for Key-Value Coding, the keys are always strings.

In fact, the documentation states that even when you give valueForKey: an NSString, it will invoke objectForKey: anyway unless the string starts with an @, in which case it invokes [super valueForKey:], which may call valueForUndefinedKey: which may raise an exception.

like image 133
gronzzz Avatar answered Feb 27 '26 18:02

gronzzz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!