Convert JSON String into NSDictionary with same order [duplicate] - objective-c

I have a JSON array returning from a request.
Data is as such (it comes from external source and cannot be changed from server):
[{"clients":
{"name":"Client name here","telephone":"00000","email":"clientemail#hotmail.com","website":"www.clientname.com"}
}]
I receive the JSON array in this order.
I have the below Objective-C:
//jsonString is the json string inside type NSString.
NSMutableDictionary *tempDict = [jsonString JSONValue];
NSMutableDictionary *clients = [tempDict objectForKey:#"clients"];
for(NSString *key in clients) {
id value = [tempDict objectForKey:key];
for(NSString *itemKey in key) {
NSLog(#"ITEM KEY %#: ",itemKey);
}
}
The order it prints keys is:
telephone
email
name
web site
I need it to print how it is received (eg):
name
telephone
email
web site
I have read that Dictionaries are unsorted by definition so am happy to use an Array instead of a dictionary.
But I have seen SEVERAL threads on StackOverflow regarding possible solution (using keysSortedByValueUsingSelector):
Getting NSDictionary keys sorted by their respective values
Can i sort the NSDictionary on basis of key in Objective-C?
sort NSDictionary keys by dictionary value into an NSArray
Can i sort the NSDictionary on basis of key in Objective-C?
I have tried them and am getting nowhere. Not sure if it is just my implementation which is wrong.
I tried (attempt 1):
NSArray *orderedKeys = [clients keySortedByValueUsingComparator:^NSComparisonResult(id obj1, id obj2){
return [obj1 compare:obj2];
}];
for(NSString *key in orderedKeys) {
id value = [tempDict objectForKey:key];
for(NSString *keyThree in key) {
NSLog(#"API-KEY-ORDER %#: ",keyThree);
}
}
Receive error: [__NSArrayM keySortedByValueUsingComparator:]: unrecognized selector sent to instance.
Also tried (attempt 2):
NSArray *sortedKeys = [[clients allKeys] sortedArrayUsingSelector: #selector(compare:)];
NSMutableArray *sortedValues = [NSMutableArray array];
for (NSString *key in sortedKeys){
[sortedValues addObject: [tempDict objectForKey: key]];
//[sortedValues addObject: [all objectForKey: key]]; //failed
}
But another error on selector even though clients is a NSMutableDictionary.
[__NSArrayM allKeys]: unrecognized selector sent to instance 0x4b6beb0
I am at the point where I think I am going to iterate over the NSMutableDictionary and manually place them into a new NSMutableArray in the correct order.
Any ideas would be very much appreciated?
OR anybodies code snippet attempt at my problem would be equally appreciated.

Not only is NSDictionary in principle unordered, but so are JSON objects. These JSON objects are identical:
[{"clients":
{"name":"Client name here","telephone":"00000","email":"clientemail#hotmail.com","website":"www.clientname.com"}
}]
[{"clients":
{"website":"www.clientname.com","name":"Client name here","telephone":"00000","email":"clientemail#hotmail.com"}
}]
If the server wants to have ordered keys, it needs to send an array. Of course you can just use the keysSortedByValueUsingComparator: method to get the keys in a sorted order.

First, the exception you're seeing is because the selector name is incorrect. You should use keysSortedByValueUsingComparator.
Second, you can't sort the keys, because the order in which you're getting them from the server doesn't seem to be in any particular order. If you MUST have them in that order, then send them from the server with a tag ("index") and then sort by this tag.

Related

Get all keys of an NSDictionary as an NSArray

Is it possible to get all the keys from a specific NSDictionary as a seperate NSArray?
Just use
NSArray*keys=[dict allKeys];
In general, if you wonder if a specific class has a specific method, look up Apple's own documentation. In this case, see NSDictionary class reference. Go through all the methods. You'll discover many useful methods that way.
Yes it's possible. Use allKeys method:
NSDictionary *yourDictionary;
NSArray * yourKeys
yourKeys = [yourDictionary allKeys];
And if you want to get all keys and values, here's what you do:
for (NSString *key in dictionary) {
id value = dictionary[key];
NSLog(#"Value: %# for key: %#", value, key);
}

Sorting a mutable array using a dictionary key

I am trying to create a simple mutable array with a single key ("dayCounter") that I intend to use for sorting. I've read loads of examples on line, but no joy.
So I create this array. Note the first entry is a NSDictionary object. (The other objects are text)
cumArray = [NSMutableArray arrayWithObjects:[NSMutableArray arrayWithObjects:
[NSDictionary dictionaryWithObject:[NSString stringWithFormat:#"%i", dayCounter] forKey:#"dayCounter"],[[dailyArray objectAtIndex:x]objectAtIndex:0],[[dailyArray objectAtIndex:x]objectAtIndex:1],[[dailyArray objectAtIndex:x]objectAtIndex:2], nil],nil];
I save the array in a plist and everything looks great after the load.
However, when I come to sort the array, the program crashes. I have tried every combination of the following:
NSSortDescriptor *aSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"dayCounter" ascending:YES];
[cumArray sortUsingDescriptors:[NSArray arrayWithObject:aSortDescriptor]];
Do I need a dictionary item to act as a key? Can I sort on the first object any easier? Any help is much appreciated.
Sometimes using too many nested expressions can obscure what's really going on. For example, the 'simple' mutable array you created actually contains a nested mutable array, rather than directly containing the dictionaries you're trying to sort.
So instead of this:
cumArray = [NSMutableArray arrayWithObjects:[NSMutableArray arrayWithObjects:
[NSDictionary dictionaryWithObject:[NSString stringWithFormat:#"%i", dayCounter] forKey:#"dayCounter"],[[dailyArray objectAtIndex:x]objectAtIndex:0],[[dailyArray objectAtIndex:x]objectAtIndex:1],[[dailyArray objectAtIndex:x]objectAtIndex:2], nil],nil];
try doing this
NSDictionary *dict1 = [NSDictionary dictionaryWithObject:[NSString stringWithFormat:#"%i", dayCounter]
forKey:#"dayCounter"]
NSArray *objs = [dailyArray objectAtIndex:x];
NSDictionary *dict2 = [objs objectAtIndex:0];
NSDictionary *dict3 = [objs objectAtIndex:1];
NSDictionary *dict4 = [objs objectAtIndex:2];
// Note: You might want to temporarily log the values of dict2 - 4 here to make sure they're
// really dictionaries, and that they all actually contain the key 'dayCounter'.
cumArray = [NSMutableArray arrayWithObjects:dict1, dict2, dict3, dict4, nil];
Assuming that you really have a mutable array of dictionaries, each of which contains the key dayCounter, the sort descriptor you showed in your example should work just fine.
Your setup makes no sense. You are saying yourself that only the first object in the array is a dictionary that contains the key `#"dayCounter" ("The other objects are text"). How is it supposed to be sorted if only one object contains the sort criteria?
You need to sort the array with a method, like - (NSComparisunResult)compareDict
If you have to compare 2 dictionaries and determine which one should be ordered above the other ( NSOrderedAscending ) then you need to "extend" NSDictionary:
#interface NSDictionary (SortingAdditions) {}
- (NSComparisonResult)compareTo:(NSDictionary *)other;
#end
#implementation NSDictionary (SortingAddictions)
- (NSComparisonResult)compareTo:(NSDictionary *)other
{
if( [self count] > [other count] )
{ return NSOrderedAscending; }
}
#end
This method will sort NSDictionaries according to the amount of objects that they contain.
Other values you can return here are: NSOrderedDescending and NSOrderedSame.
Then you can sort the mutable array with:
[SomeMutableArray sortUsingSelector:#selector(compareTo:)];
Keep in mind that every object in the array will need to be an NSDictionary, otherwise you will get an exception: unrecognized selector sent to instance blabla
You can do the same thing for any type of object, if the array contains both NSStrings, NSNumbers and NSDictionaries you should take a different approach

Enumerating a NSArray of different objects

NSMutableArray *array = [NSMutableArray arrayWithObjects:#"Hello World!", [NSURL URLWithString:#"http://www.apple.com"], nil];
for (id *object in array) {
NSLog(#"Class name: %#", [object className]);
}
Given the above array of varying objects what is the proper way to fast enumerate thru them? Using the above code I do see my log statement properly, but Xcode does complain with the following message
Invalid receiver type 'id*' on my NSLog statement.
That should be:
for (id object in array) {
// ...
That is because id already is a pointer, see the section on id in Apples The Objective-C Programming Language for details on it.

Print_r equivalent for XCode? I just want to see my array's content

I am a web developer trying to make it in an Xcode world, and I need to see the contents of an array I have in my console, what are my options?
There's no need to iterate through an array just to print it.
All the collection types have a -description method that returns a NSString of their contents. Just use the object format specifier %#
NSLog(#"%#", array);
As an additional note you can dynamically print NSArrays and other objects in the debugger using po object. This uses the same description method that NSLog does. So it's not always necessary to litter your code with NSLogs, especially if you're already in the debugger.
You could try something like this:
NSArray *array = [NSArray arrayWithObjects: #"a", #"b", #"Hello World", #"d", nil];
for (id obj in array) {
NSLog(#"%#", obj);
}
... which would log each item in the array to the console in their own separate NSLog messages.
Or if you want to see your NSDictionary's content (which is comparable to a PHP associated array()), you could use:
for (id key in [dictionary allKeys]) {
NSLog(#"Key: %#, Value: %#", key, [dictionary objectForKey:key]);
}

Accessing objects in NSMutableDictionary by index

To display key/values from an NSMutableDictionary sequentially (in a tableview), I need to access them by index. If access by index could give the key at that index, I could than get the value. Is there a way to do that or a different technique?
You can get an NSArray containing the keys of the object using the allKeys method. You can then look into that by index. Note that the order in which the keys appear in the array is unknown. Example:
NSMutableDictionary *dict;
/* Create the dictionary. */
NSArray *keys = [dict allKeys];
id aKey = [keys objectAtIndex:0];
id anObject = [dict objectForKey:aKey];
EDIT: Actually, if I understand what you're trying to do what you want is easily done using fast enumeration, for example:
NSMutableDictionary *dict;
/* Put stuff in dictionary. */
for (id key in dict) {
id anObject = [dict objectForKey:key];
/* Do something with anObject. */
}
EDIT: Fixed typo pointed out by Marco.
you can get an array of all the keys with the allKeys method of the dictionary; and then you can access the array by index. however, a dictionary by itself does not have an inherent ordering, so the ordering of the keys you get before and after a change to the dictionary can be completely different