JsonModel NSString transform null to empty string - ios

I am using JSONModel in my application. Is it possible to prepare category with JSONValueTransformer that will transform nil/null NSString to empty string (#""). So far when property in json response is null, my property in object becomes #"".
Because the whole API is not very well (it's external) I would like to avoid overriding initWithDictionary in every object and use just ValueTransformer for every JSONModel class with NSString property and map it to correct string or empty string if nil/null.

After getting response, run following loop with your response dictionary and its key.
for (id dictionary in [[responseDictionary valueForKey:#"responseKey"] allKeys] )
{
([[responseDictionary valueForKey:#"responseKey"] valueForKey:dictionary] == [NSNull null]) ? [[responseDictionary valueForKey:#"responseKey"] setValue:#"" forKey:dictionary] :[[responseDictionary valueForKey:#"responseKey"] setValue:[[responseDictionary valueForKey:#"responseKey"] valueForKey:dictionary] forKey:dictionary];
}

Related

NSMutableDictionary returning null

I created an NSMutableDictionary in NSObject class like
#property (nonatomic, strong) NSMutableDictionary<NSNumber *, NSString *> *requestComments;
and saved the data in this variable when comes through API.
But when I am sending the key to get the value it is returning null every time.
To get the value I am doing like this
NSLog(#"%#",dataManager.requestComments[serviceRequest.RequestId]);
// serviceRequest.RequestId is returning NSNumber.
the output I'm getting is "(null)"
if I use to like this then it returns a value
NSLog(#"%#",[dataManager.requestComments valueForKey:#"30221"]);
Why it is returning null in the above case.
Based on your question, this should work
NSLog(#"%#",dataManager.requestComments[[serviceRequest.RequestId stringValue]]);
Because you gave the key as NSString and you are expecting it to return based on an NSNumber. You need to look at the code which you are using to store this dictionary.
Update
You have mentioned that key is of NSNumber type. But you are passing a string in valueForKey and getting a valid object back. You should check how you are forming this dictionary from API response.
Because you declared requestComment to be aNSDictionary which keys are NSNumbers and values are NSString doesn't oblige it to respect it.
Sample:
_requestComments = [[NSMutableDictionary alloc] init];
[_requestComments setObject:[NSNumber numberWithInt:34] forKey:#"54"]; // => Warning: Incompatible pointer types sending 'NSNumber * _Nonnull' to parameter of type 'NSString * _Nonnull'
id obj = [NSNumber numberWithInt:35];
id key = #"55";
[_requestComments setObject:obj forKey:key];
NSLog(#"[_requestComments objectForKey:#\"55\"]: %#", [_requestComments objectForKey:#"55"]); //Warning: Incompatible pointer types sending 'NSString *' to parameter of type 'NSNumber * _Nonnull'
NSLog(#"[_requestComments objectForKey:#(55)]: %#", [_requestComments objectForKey:#(55)]);
Logs:
$>[_requestComments objectForKey:#"55"]: 35
$>[_requestComments objectForKey:#(55)]: (null)
Okay, I used id to lure the compiler, but id is a common returned "class", in objectAtIndex:, etc. It's common in JSON parsing when you think a object will be a NSString but is in fact a NSNumber of (inverse).
Before doing requestComments[serviceRequest.RequestId], enumerate ALL the keys value & class and ALL objects value & class. You can check it like this:
for (id aKey in _requestComments)
{
id aValue = _requestComments[aKey];
NSLog(#"aKey %# of class %#\naValue %# of class %#", aKey, NSStringFromClass([aKey class]),aValue, NSStringFromClass([aValue class]));
}
Then you can try to track where you put a wrong key (class).

Concatenate Strings for Dictionary:syntax error

The following code to conditionally concatenate strings for a dictionary seems to work up to the point where I try to place the concatenated result in the dictionary. Can anyone see the error?
NSDictionary *jsonDictionary;
NSString* dictString = #"#\"first\":first,#\"last"
NSString *dictString2=dictString;
if (date.length>0&&![date isKindOfClass:[NSNull class]]) {
//only include this key value pair if the value is not missing
dictString2 = [NSString stringWithFormat:#"%#%s", dictString, "#\"date\":date"];
}
jsonDictionary = #{dictString2}; //syntax error. Says expected colon but that does not fix anything
The syntax for creating an NSDictionary using object literals is:
dictionary = #{key:value}
(and optionally, it can contain multiple key/value pairs separated by commas, but never mind that right now.)
Where "key" and "value" are both NSObjects.
Your line that is throwing the error only contains 1 thing. The contents of a the string in dictString2 has nothing to do with it.
It looks to me like you are trying to build a JSON string manually. Don't do that. Use NSJSONSerialization. That class has a method dataWithJSONObject that takes an NSObject as input and returns NSData containing the JSON string. That's how you should be creating JSON output.
Creating an NSDictionary with values that may be null:
NSDictionary *dict = #{
#"key" : value ?: [NSNull null],
};
When serializing a dictionary, NSNulls are translated to null in the JSON.
If you want to exclude such keys completely, instead of having them with a null value, you'll have to do more work. The simplest is to use an NSMutableDictionary and test each value before adding it.

How can I check for an empty object within an NSArray

I'd like to check for an empty object (i.e. an object of an array which doesn't have a value) within an array which gets its data from a file.
As an example, if my array contains 12 objects (all NSString) and the object at index 11 doesn't return a value when its description is printed into the debug section of Xcode. I want to check if that is the case and respond accordingly. I already tried
if (!([MY_ARRAY objectAtIndex:11] == nil))
{
//Some Stuff
}
else
{
//Some other Stuff
}
which didn't work.
Any help is appreciated.
The description method is for debugging. You should not use it in your program logic. What are these objects, and what do they contain? Can you modify the objects to add an "isEmpty" property?
If you use NSNull, you'd use code like this:
NSArray *array = #{#"String", #(4), [NSNull null], #"Another string");
for (id anObject in array)
{
if (anObject =! [NSNull null]))
{
//Some Stuff
}
else
{
//Some other Stuff
}
}
You can check the length of the string: [string length] > 0
an object is an array cannot be nil, but you can use [NSNull null] which is an "object equivalent" to nil
As Jerome Diaz states, objects in an array can't be nil. The only option you have is to check the count property of the array if it reflects an expected value, or you can inspect the type/class of the object in the array. A safe way to include empty object into array is [NSNull null], but this is the task for the method that fills the array, not the one that reads it.
You can check the class type of an object in array with isKindOfClass or isMemberOfClass.

how to handle boolean value with AFNetworking parsing JSON

I have some JSON that comes back like this:
"items":[
{
"has_instore_image": false
}
]
If I output the value like this:
NSLog(#"has_instore_image val: %#", [item objectForKey:#"has_instore_image"]);
I get
has_instore_image val: 0
but if I test like this:
if([item objectForKey:#"has_instore_image"]==0){
NSLog(#"no, there is not an instore image");
}else{
...
It always goes to the else statement... hmmm.. How would you suggest I get the BOOL value and test? I've read through the BOOL questions here and am just confused this is not working as I'd anticipate.
thx
NSDictionary's instance method objectForKey returns an id, not a primitive value.
If it's a boolean, int, float, etc number-like value in JSON, it will serialized to an NSNumber by Apple's NSJSONSerialization class and most/all other common JSON parsers in iOS.
If you want to get the BOOL value out of it, you can do something like this:
BOOL has_instore_image = [[item objectForKey:#"has_instore_image"] boolValue];
You are comparing a pointer with an integer here
[item objectForKey:#"has_instore_image"]==0
You should use
[item objectForKey:#"has_instore_image"].integerValue==0
Also note that a BOOL of NO equals 0.
The NSLogstatement in your code prints a 0, but only because if you give NSLogan object as parameter, the objects descriptionis called.
i will suggest to hold these id type (returned from dictionary) to NSNumber .
NSNumber *boolNum=(NSNumber*)[item objectForKey:#"has_instore_image"];
after that you can get bool value from boolNum
[boolNum boolValue]
try this
if([boolNum boolValue]==NO){
NSLog(#"no, there is not an instore image");
}else
{
}

How do I get properties out of NSDictionary?

I have a webservice that returns data to my client application in JSON. I am using TouchJson to then deserialize this data into a NSDictionary. Great. The dictionary contains a key, "results" and results contains an NSArray of objects.
These objects look like this when printed to log i.e
NSLog(#"Results Contents: %#",[resultsArray objectAtIndex:0 ]);
Outputs:
Results Contents: {
creationdate = "2011-06-29 22:03:24";
id = 1;
notes = "This is a test item";
title = "Test Item";
"users_id" = 1;
}
I can't determine what type this object is. How do I get the properties and values from this object?
Thanks!
To get the content of a NSDictionary you have to supply the key for the value that you want to retrieve. I.e:
NSString *notes = [[resultsArray objectAtIndex:0] valueForKey:#"notes"];
To test if object is an instance of class a, use one of these:
[yourObject isKindOfClass:[a class]]
[yourObject isMemberOfClass:[a class]]
To get object's class name you can use one of these:
const char* className = class_getName([yourObject class]);
NSString *className = NSStringFromClass([yourObject class]);
For an NSDictionary, you can use -allKeys to return an NSArray of dictionary keys. This will also let you know how many there are (by taking the count of the array). Once you know the type, you can call
[[resultsArray objectAtIndex:0] objectForKey:keyString];
where keyString is one of #"creationdate", #"notes", etc. However, if the class is not a subclass of NSObject, then instead use:
[[resultsArray objectAtIndex:0] valueForKey:keyString];
for example, you probably need to do this for keystring equal to #"id".

Resources