Compare String and Array in iOS - ios

I have hired a iOS developer to create an app which will be backed by the REST API. Now I'm stuck with a problem with one output.
There are Public and Private Groups, if group is Private, the API will return following in json format:
privacy":{"value":"1"},
and if the group is Public, the API will return following in json format:
"privacy":[]
The iOS developer says that this output is incorrect while on the other hand API developer believe this is correct output. Can anyone please tell me is this output correct to be used in iOS app or it's not correct?
iOS Developer days he can't compare String and Array.

Yes it's correct, given there is no such thing as incorrect with JSON, as there is no schema to conform to. As long as it's legal, it's OK.
The iOS developer can test the type of the "privacy" value after it's been deserialised:
id value = jsonDict[#"privacy"];
if ([value isKindOfClass:[NSDictionary class]]) {
// Value is dictionary
NSDictionary *dictValue = (NSDictionary *)value;
NSString *number = dictValue[#"value"]; // This should be a number, not a string!
} else if ([value isKindOfClass:[NSArray class]]) {
// Value is array
} else {
// Value is illegal. Report error.
}
I will say that it should be:
{"value":1}
as 1 is a number, not a string.

Yes, iOS developer can check response.
But there should be consistency in JSON response.
It is not correct way that one API give response in array and other in dictionary.
It should be either array or string that would be preferable for iOS developer.
Output should be:
{
"privacy":[{"value":1}]
}
For validating JSON response you can use http://jsonlint.com/

The API is designed incorrectly, as it provides various data types for the privacy key (and no schema defines how this should behave). Once it's a dictionary, once it's an empty array.
I'd suggest using an array in any case.
Private:
privacy : [ {"value" : true} ]
Public:
privacy : []
However, it's possible to concatenate array to string and then compare with string (using let stringRepresentation = ",".join(array))

Related

Sort array based on second array order

I have an array from a plist and each value contains an key and a string and a secondary array that I get from a json file online. I want to order the secondary array based on the keys in the first array.
I want to achieve something like this:
array1:
Item0 - EUR
- String
Item1 - USD
- String
Item2 - AUD
- String
etc
array2:
Item0 - AUD
- 123.242
Item1 - EUR
- 535.123
Item2 - USD
- 325.646
etc
I have the same key index on both but I want to get the value for the key index from array2 based on the order of the key index in array1.
I have researched online but I cannot find a suitable solution that I can understand how to implement it.
How can I implement this?
Here is the plist file - https://gist.github.com/iulianvarzaru/11c400ba1edf4a165082
And the json file - https://gist.github.com/iulianvarzaru/1915e02a9201c57f49b3
Given that the JSON file you've linked to doesn't contain an array but a dictionary, you can simply iterate over array1 from the plist file. Each element of that array is a dictionary with a "Cod" key and a "Descriere" key. Get the value for the "Cod" key and then simply use that value as the key into the dictionary from the JSON file.
NSDictionary* jsonFileDict = ...;
NSDictionary* jsonFileInnerDict = jsonFileDict[#"rate"];
for (NSDictionary* dict in array1)
{
NSString* code = dict[#"Cod"];
NSNumber* jsonNumber = jsonFileInnerDict[code];
// Do something with jsonNumber
}
It sounds like these are key-value pairs, in which case, you can convert it to a Map, and then do direct lookups.
If you can manipulate the JSON file as JSON, then it reduces a conversion, but may not be the most efficient implementation.
Caveats:
This method assumes that you wont have key overloading (which is possible in a numeric array, but not in a map)
This requires a conversion from one data structure to another
EDIT: (due to increased information by OP).
The JSON file you receive doesn't contain an array, it contains an object. Thus, all the values are direct-lookup. So, you can traverse your array in Obj-c, and directly access the corresponding values in the JSON.
Sorry about the lack of actual code-samples.
You are dealing with a dictionary in the response, not an array.
You should transform it to something like
{
#"currency": #"EUR",
#"value": 123.45
}
create and sort it it like
NSArray *keys = #[#"EUR",#"USD",#"AUD"];
NSDictionary *dict = #{#"AUD":#(123.242), #"EUR": #(535.123), #"USD": #(325.646)};
NSMutableArray *result = [#[] mutableCopy];
for (NSString *key in keys) {
[result addObject:#{#"value":dict[key], #"currency": key}];
}
NSLog(#"%#", result);
(
{
currency = EUR;
value = "535.123";
},
{
currency = USD;
value = "325.646";
},
{
currency = AUD;
value = "123.242";
}
)
Or write a model class that can handle this information.

iOS: Can someone explain CFDictionaryRef for me?

I'm doing some testing on AddressBook and though I can get the data I am looking for I'm curious about how it is delivered. Specifically CFDictionaryRef. When I cast this to a NSDictionary and log to console I just get a string value, not a key=value pair. If I try to log allKeys my test app breaks.
Here's the code snippet I'm using:
if ([contactName isEqualToString:ownerName]) {
//get reference to their email addresses
ABMultiValueRef contactEmails = ABRecordCopyValue(thisPerson, kABPersonEmailProperty);
//loop
for (NSUInteger e = 0; e < ABMultiValueGetCount(contactEmails); e++){
CFDictionaryRef thisPersonCFEmailDict = ABMultiValueCopyValueAtIndex(contactEmails, e);
NSDictionary* thisPersonEmailDict = (__bridge NSDictionary*)thisPersonCFEmailDict;
NSLog(#"%#", [thisPersonEmailDict allKeys]);
}
}
You're assuming ABMultiValueCopyValueAtIndex() returns a CFDictionaryRef. It doesn't. It returns whatever value is appropriate for that multi-value, as evidenced by the CFTypeRef return value.
You can use ABMultiValueGetPropertyType() to find out what type of value a particular multi-value record has. If that returns kABDictionaryPropertyType then you know it's a dictionary, but in your case it's probably returning kABStringPropertyType. It could also return kABInvalidPropertyType, which may indicate that the multi-value contains different types. If so, you'll need to resort to using CFGetTypeID() to identify the type of value returned from ABMultiValueCopyValueAtIndex().
CFDictionaryRef is the Core Foundation counterpart of NSDictionary. Because NSDictionary and CFDictionary are “toll-free bridged,” you can substitute a CFDictionary object for a NSDictionary object in your code (with appropriate casting). Although they are corresponding types, CFDictionary and NSDictionary do not have identical interfaces or implementations, and you can sometimes do things with CFDictionary that you cannot easily do with NSDictionary. Toll-free bridging, means that you can use the same data type as the parameter to a Core Foundation function call or as the receiver of an Objective-C message.

iOS, JSON-RPC and NSJSONSerialization: Dealing with null values

I am using JSON-RPC to communicate between iOS application and the server. Some return values of the server are optional.
Considering the combination of technologies I am using, is it better to return these null values like {"telephone": null} or by completely omitting the "telephone" element in the response?
Futher explanation of what I am asking:
It doesn't look like the JSON-RPC spec specifies much to do with the method result (please correct me if I'm wrong) and clearly not sending loads null elements would improve performance and reduce bandwidth somewhat. What I'm most interested in though is the best approach from an iOS NSJSONSerialization perspective. Is it easier/better to check for whether a key exists in an NSDictionary or whether an existing key has a null value?
I'm using a completely different technique, somewhat unorthodox for sure, since my code is dealing with huge data sets and I really hate having to make tests for NSNull on each value. What I did was subclass NSNull, so when dealing with data, I can test if its numeric value is 0, if its string length is 0, etc.
#implementation NSNull (JSON)
- (NSUInteger)length { return 0; }
- (NSInteger)integerValue { return 0; };
- (CGFloat)floatValue { return 0; };
- (NSString *)description { return #"0(null)"; } // so I know it was NSNull in log messages
- (NSArray *)componentsSeparatedByString:(NSString *)separator { return #[]; }
- (id)objectForKey:(id)key { return nil; }
- (BOOL)boolValue { return NO; }
#end
EDIT: I used this exact same code in an e-commerce shipping app. There were literally thousands of objects getting returned by tens of different APIs - having to look at each item to see if it was [NSNull null] would have been a nightmare. I tried to write a routine to groom results, it would recursively look at dictionaries and arrays and reconstruct the object, but it got too complicated.
In any case, I never even once had an issue with this solution. Obviously YMMV.
First of all {"telephone": "null"} is not a null value. There are quotes so actually telephone property has string value with text "null". Server needs to send {"telephone": null} - without quotes.
I'd go with listing all relevant properties that your app needs in response and put null as a value if there is not value. Then you can easily check in NSDictionary you get from NSJSONSerialization if value for key is NSNull.
if ([dictionaryValue isKindOfClass:[NSNull class]])
myThink.myProperty = nil;
I've packed the check in a function, if anyone interested.
-(id)checkNull:(id)object{
if([object isKindOfClass:[NSNull class]])return nil;
else return object;
}

Integer from .plist

I'm new to plists, and I really need to use one. What I have is a plist where different numbers are stored, under two dictionaries. I need to get that number which is stored, and make it an integer. This process will be run from a method called 'readPlist.
The plist is called 'properties.plist'. The first dictionary is called 'Enemies'. It contains various other dictionaries, which will have the name stored in the NSMutableString called 'SpriteType'. The name of the number will have the format 'L - %d', with the %d being an integer called 'LevelNumber'.
If possible, can someone give me the code on how to get that integer using the information, and the names of dictionaries above.
I have looked around at how to access plists, but the code that people have shown doesn't work.
Thanks in advance.
EDIT: Too make it more understandable, this is my plist. What i want in an integer, called 'SpriteNumber' to be equal to the value of 'L - %d'
If you read the contents of your plist into a dictionary (I won't tell you how to do it, but this is the tutorial I refer to often), then it's a matter of getting the string out of the key for the level with [[myDictionary objectForKey:#"key"]stringValue];. Then, using of NSString's extremely helpful -stringByReplacingOccurencesOfString:withString: to get rid of the "L -" part and only get a numerical value. Finally, get an integer from the string with [myString intValue].
well, the easiest way would be something like :
-(int) getMosquitoCountForLevel:(int) level {
int mosquitoCount=0;
NSString *gsFile = #"whateverFullyQualifiedFileNameYourPlistIs";
NSDictionary* definitions = [NSDictionary dictionaryWithContentsOfFile:gsFile];
NSDictionary* mosquitos = [definitions objectForKey:#"Mosquito"];
if(mosquitos) {
NSString *levelKey = [NSString stringWithFormat:#"L - %d",level];
NSNumber *mosquitoCountAsNumber = [mosquitos objectForKey:levelKey];
if(mosquitoCountAsNumber) {
mosquitoCount=[mosquitoCountAsNumber intValue];
} else {
CCLOGERROR(#"%# - Mosquito definitions in %# does not contain a en entry for level %#.",self.class,gsFile,levelKey);
}
} else {
CCLOGERROR(#"%# - file %# does not contain a Mosquito dictionary.",self.class,gsFile);
}
return mosquitoCount;
}
this compiles but not tested with actual data.

How to parse JSON in iOS App

Im getting a response from twitter in the form of a string,
What I need is to send the parts where is a comment to an array,
here an example of the string
[{"geo":null,"coordinates":null,"retweeted":false,...
"text":"#KristinaKlp saluditos y besos d colores!"},{"geo":null,"coordinates...
so what I really need are the posts after "text":" =
#KristinaKlp saluditos y besos d colores!
So, how can I take the string and parse it so I get all the messages in an array hopefully?
Thanks a lot!
I haven't done JSON parsing myself in an iOS App, but you should be able to use a library like the json-framework. This library will allow you to easily parse JSON and generate json from dictionaries / arrays (that's really all JSON is composed of).
SBJson docs:
JSON is mapped to Objective-C types in the following way:
null -> NSNull
string -> NSString
array -> NSMutableArray
object -> NSMutableDictionary
true -> NSNumber's -numberWithBool:YES
false -> NSNumber's -numberWithBool:NO
integer up to 19 digits -> NSNumber's -numberWithLongLong:
all other numbers -> NSDecimalNumber
Since Objective-C doesn't have a dedicated class for boolean values,
these turns into NSNumber instances. However, since these are
initialised with the -initWithBool: method they round-trip back to JSON
properly. In other words, they won't silently suddenly become 0 or 1;
they'll be represented as 'true' and 'false' again.
As an optimisation integers up to 19 digits in length (the max length
for signed long long integers) turn into NSNumber instances, while
complex ones turn into NSDecimalNumber instances. We can thus avoid any
loss of precision as JSON allows ridiculously large numbers.
#page objc2json Objective-C to JSON
Objective-C types are mapped to JSON types in the following way:
NSNull -> null
NSString -> string
NSArray -> array
NSDictionary -> object
NSNumber's -initWithBool:YES -> true
NSNumber's -initWithBool:NO -> false
NSNumber -> number
#note In JSON the keys of an object must be strings. NSDictionary
keys need not be, but attempting to convert an NSDictionary with
non-string keys into JSON will throw an exception.
NSNumber instances created with the -numberWithBool: method are
converted into the JSON boolean "true" and "false" values, and vice
versa. Any other NSNumber instances are converted to a JSON number the
way you would expect.
Tutorials
Are there any tutorials? Yes! These are all tutorials provided by
third-party people:
JSON Framework for iPhone - a Flickr tutorial in three parts by John
Muchow. JSON Over HTTP On The iPhone - by Dan Grigsby. AS3 to Cocoa touch: JSON by Andy Jacobs.
There are other libraries you can check out as well like TouchJSON, JSONKit, Yet Another JSON Library
NSJSONSerialization does the job of converting your JSON data into usable data structures as NSDictionary or NSArray very well. I recommend it, even more because it is part of the Cocoa public interface and it is maintained by Apple.
However, if you want to map the content of your JSON to your Objective-C objects, you will have to map each attribute from the NSDictionary/NSArray to your object property. This might be a bit painful if your objects have many attributes.
In order to automatise the process, I recommend you to use the Motis category (personal project) on NSObject to accomplish it, thus it is very lightweight and flexible. You can read how to use it in this post. But just to show you, you just need to define a dictionary with the mapping of your JSON object attributes to your Objective-C object properties names in your NSObject subclasses:
- (NSDictionary*)mjz_motisMapping
{
return #{#"json_attribute_key_1" : #"class_property_name_1",
#"json_attribute_key_2" : #"class_property_name_2",
...
#"json_attribute_key_N" : #"class_property_name_N",
};
}
and then perform the parsing by doing:
- (void)parseTest
{
NSData *data = jsonData; // <-- YOUR JSON data
// Converting JSON data into NSArray (your data sample is an array)
NSError *error = nil;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
if (error)
return; // <--- If error abort.
// Iterating over raw objects and creating model instances
NSMutableArray *parsedObjects = [NSMutableArray array];
for (NSDictionary *rawObject in jsonArray)
{
// Creating an instance of your class
MyClass instance = [[MyClass alloc] init];
// Parsing and setting the values of the JSON object
[instance mjz_setValuesForKeysWithDictionary:rawObject];
[parsedObjects addObject:instance];
}
// "parseObjects" is an array with your parsed JSON.
// Do whatever you want with it here.
}
The setting of the properties from the dictionary is done via KeyValueCoding (KVC) and you can validate each attribute before setting it via KVC validation.
I recently had to do this. After looking at the various options out there, I threw JSONKit into my app (I found it on a JSON discussion on StackOverflow). Why?
A) It is VERY VERY simple. I mean, all it has is the basic parsing/emitting functions, what more do you need?
B) It is VERY VERY fast. No overhead - just get the job done.
I should note, I had never done JSON before - only heard of the term and didn't even know how to spell it. I went from nothing, to a working app, in about 1 hour. You just add one class to your app (the .h, .m), instantiate it, and call the parser to a dictionary object. Voila. If it contains an array, you just get the objectForKey, cast it as an NSArray. It's really hard to get simpler than that, and very fast.
For a good comparison of the speed of the different libraries for JSON parsing on iOS, take a look at The Ultimate Showdown.
-(IBAction)btn_parse_webserivce_click:(id)sender
{
// Take Webservice URL in string.
NSString *Webservice_url = self.txt_webservice_url.text;
NSLog(#"URL %#",Webservice_url);
// Create NSURL from string.
NSURL *Final_Url = [NSURL URLWithString:Webservice_url];
// Get NSData from Final_Url
NSData* data = [NSData dataWithContentsOfURL:
Final_Url];
//parse out the json data
NSError* error;
// Use NSJSONSerialization class method. which converts NSData to Foundation object.
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:data
options:kNilOptions
error:&error];
// Create Array
NSArray* Response_array = [json objectForKey:#"loans"];
NSLog(#"Array: %#", Response_array);
// Set Response_array to textview.
self.txt_webservice_response.text = [NSString stringWithFormat:#"%#"
,Response_array];
}
How about NSJSONSerialization? I've been using it to parse JSON
http://developer.apple.com/library/ios/#documentation/Foundation/Reference/NSJSONSerialization_Class/Reference/Reference.html

Resources