IOS Sort NSDictionary [duplicate] - ios

This question already has answers here:
NSDictionary with ordered keys
(9 answers)
Closed 9 years ago.
to start, this is my code :
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL
URLWithString:url]];
NSData *response = [NSURLConnection sendSynchronousRequest:request
returningResponse:nil error:nil];
NSDictionary *publicTimeline = [NSJSONSerialization JSONObjectWithData:response options:0 error:&jsonParsingError];
for (NSObject* key in publicTimeline) {
id value = [publicTimeline objectForKey:key];
NSLog(#"%#", key);
}
I take few news on a webservice, and i show it in a tableView.
My problem is that these news aren't show in order.
In my webservice, the news are in order, for example i have :
{"0":{"title":"News1"}}
{"1":{"title":"News2"}}
{"2":{"title":"News3"}}
etc..
but in the loop, i "loose" this order :/ And i want to have my news in this order, first the news with the index "0" after "1" etc...
(the NSDictionary seems to loose this order, for example, after my code, i have in my tableview, the news : "2", "0", "1", and not my news "0", "1", "2". )
(i tried some answers, but none seems to work in my case :( )
SOmeone to help me ? thx,

This is what I used last time to sort the keys of my dictionary. Hope it will be easier for you to implement it :)
NSMutableArray *sortedArray = [NSMutableArray arrayWithArray:publicTimeline.allKeys];
[sortedArray sortUsingSelector:#selector(localizedStandardCompare:)];
And you should have your sorted keys in sortedArray

You can work with that :
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:publicTimeline];
[dict keysSortedByValueUsingComparator:^(id obj1, id obj2) {
return (NSComparisonResult)[obj1 compare:obj2];
}];
And then USE dict instead of publicTimeline.
Hope that will help.

Dictionaries don't have an order. Just because the server generates your JSON in a particular order doesn't mean that it is / can be maintained when you deserialise with NSJSONSerialization.
If you need to maintain the order, either:
A. Get all of the keys from the dictionary and sort them. Then, any time you need to access in order (by index), get the key from the array and use that (don't iterate the dictionary).
B. Use a different method to deserialise the JSON which can keep / provide data about the order in which things were processed (RestKit can do that for you).

Related

Objective-c NSDictionary to NSMutableArray in certain order

So I have this NSDictionary like so:
NSDictionary *productionSchedule = [[[NSMutableDictionary alloc]initWithDictionary:[[areaData GetProductionScheduleData:communityDesc] objectForKey:#"Root"]] autorelease];
The data for the NSDictionary is coming from an API and due to the fact that NSDictionary does not do ordering, the order of the data in API is different in the NSDictionary, so now I am trying to put the keys of the NSDictionary into an NSMutableArray to handle the ordering. In my NSDictionary I have a value called SortOrder and I am trying to put the data in NSDictionary into NSMutableArray based on this value SortOrder (I have about 389 items and the SortOrder goes from 0 - 389) How would I do this?
I have this screenshot that will show you what my data is like:
What I am trying to do is put the key 'V3C0183' but as the 82nd item (there will be 81 items before this)
I am assuming I will have to do a foreach loop like so:
NSMutableArray *prodSchedSortedKeys
for(int i = 0;i<[productionSchedule count];i++)
{
[prodSchedSortedKeys addObject: ? ];
}
I just dont know what the next step would be to add an object based off the sort order....please help.
NSDictionary *dic = //your dictionary;
NSArray<NSDictionary *> *values = dic.allValues;
[values sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
return [obj1[#"SortOrder"] integerValue] > [obj2[#"SortOrder"] integerValue];
}];
Now the dic is ordered.
But this is not the best solution of this problem. Server's data should be ordered instead, that the key like "VC31083" should in the key-value pairs too.
Edit1: sortedArrayUsingComparator: is used for normal sort of array, the performance isn't very well if the content is too large. Especially in this compare, it do addition actions: get value from dictionary, transform NSString to int, and then compare. You can Log to see how much time it spend on this sort with your data.
NSMutableDictionary/NSDictionary can't do that. Take a look at e.g. Matt Gallaghers OrderedDictionary.
Also take a look at this answer:
Getting NSDictionary keys sorted by their respective values

Parse json Data in iOS

I know it's a common question, but I am stuck with is API
How to Parse data from this API : http://dl.bahramradan.com/api/1/get/ig
it contain 20 Object and in every object there are 3 other Objects called "image",date" and "caption"
how can I store all "date" values in an NSMUtableArray in ios?
I did this :
NSString *urlStr = [NSString stringWithFormat:#"http://dl.bahramradan.com/api/1/get/ig"];
NSURL *url = [NSURL URLWithString:urlStr];
NSData *json = [NSData dataWithContentsOfURL:url];
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:json options:0 error:NULL];
NSArray *dateArray = [dict objectForKey:#"date"];
But when I run my app, it crashs on the last line, what is wrong ?
I did not check, if your JSON is valid. But there is one obvious mistake in your code: If the JSON consists of 20 objects, I assume those being contained in an array, rather than in a dict!
So first thing to change is
NSArray *array = [NSJSONSerialization JSONObjectWithData:json options:0 error:NULL];
Then, you want to extract the 'date' values for all items and combine these in another array.
Easiest way to achieve that, is by using a KVC Collection Operator
NSArray *dateArray = [array valueForKeyPath:#"#unionOfObjects.date"];
So, what '#unionOfObjects.date' does, is: going through all the objects in the array, look for each of their 'date' value and combine them in the returned array.
Check out this excellent post about KVC Collection Operators!

iOS JSON twitter response, convert to mutable

I have an app that is requesting a users list of followers. I would like to be able to change some of the data inside of the array I am getting back from twitter, but I can't seem to get it to become a proper mutable copy.
Here is my code:
NSMutableDictionary *theData = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableLeaves error:&error];
NSMutableDictionary *TWData = [[NSMutableDictionary alloc] init];
TWData = [theData mutableCopy];
NSMutableArray *data = [TWData objectForKey:#"users"];
The order this is in and doing a mutable copy FIRST is the last thing I tried. This is the code that throws an error:
[[data objectAtIndex:2] setObject:#"indeed" forKey:#"following"];
And here is the typical error message:
[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object'
I understand WHY it is giving me the error, my question is how can I make EVERYTHING (all child dictionaries and array, and all of their child dictionaries and array, etc.) mutable so I can alter the data.
Any help is great, thanks!
You can use CFPropertyListCreateDeepCopy from Core Foundation:
NSMutableDictionary* mutableData = (NSMutableDictionary*) CFBridgingRelease(CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFPropertyListRef) theData, kCFPropertyListMutableContainers));
See the CFPropertyList reference for more info. In particular, the Property List Mutability Options can be used to control what is mutable in the returned copy.

How would I use an NSMutableArray with a NSMutableDictionary

I have an NSMutableDictionary of websites
[dictionaryOfSites setObject:#"http://www.example.com" forKey:#"Example.com"];
[dictionaryOfSites setObject:#"http://www.site1.com" forKey:#"Site1"];
[dictionaryOfSites setObject:#"http://www.apple.com" forKey:#"Apple"];
I know you can't sort a dictionary. But I've read that other people have used an NSMutableArray as the key and the array can be sorted.
So if I setup a new array
[[arrayKey alloc] initWithObjects:#"Example.com", #"Site1", #"Apple", nil];
I would then modify my first snippet to
[dictionaryOfSites setObject:#"http://www.example.com" forKey:[arrayForKey objectAtIndex:0]];
[dictionaryOfSites setObject:#"http://www.site1.com" forKey:[arrayForKey objectAtIndex:1]];
[dictionaryOfSites setObject:#"http://www.apple.com" forKey:[arrayForKey objectAtIndex:2]];
In this simple problem, I had 3 sites so I "hard" coded it. How would I do the same thing if my list of sites was 100? How would the order of the sites be maintained?
If I sort my array
[arrayKey sortUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
Wouldn't index 2 become index 0? If it becomes index 0 then you can see the dictionaryOfSites has the wrong label with the URL.
So you can use a custom class (as I mentioned above in my comment), or better yet use an NSDictionary to store the values as MarkM suggested.
EDIT: "i don't have to maintain a dictionary. its a new app from the ground up."
Since you don't need to start with one big dictionary like you posted, it would be better to just store individual dictionary objects for each site in an array and not have to worry about the conversion.
// Setup the initial array
NSMutableArray *arrayOfSites = [NSMutableArray new];
[arrayOfSites addObject:#{#"Name" : #"Example.com",
#"URL" : #"http://www.example.com"}];
[arrayOfSites addObject:#{#"Name" : #"Site1",
#"URL" : #"http://www.site1.com"}];
[arrayOfSites addObject:#{#"Name" : #"Apple",
#"URL" : #"http://www.apple.com"}];
// At this point, arrayOfSites contains a dictionary object for each site.
// Each dictionary contains two keys: Name and URL with the appropriate objects.
// Now we just need to sort the array by the Name key in the dictionaries:
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"Name" ascending:YES];
[arrayOfSites sortUsingDescriptors:[NSArray arrayWithObjects:descriptor, nil]];
NSLog(#"%#", arrayOfSites);
Results:
2013-05-07 18:19:08.386 Testing App[75712:11f03] (
{
Name = Apple;
URL = "http://www.apple.com";
},
{
Name = "Example.com";
URL = "http://www.example.com";
},
{
Name = Site1;
URL = "http://www.site1.com";
} )
To access the data, you would use:
NSString *name = [[arrayOfSites objectAtIndex:indexPath.row] objectForKey:#"Name"];
Note that arrayOfSites should be a declared property of your class so that you can access it from different methods.
What you need to do is store your NSDictionary objects in the array and then access a value from that array to do the sorting if you wish. You don't actually store a new string for the sorting. You just check the value of a certain key in the dictionary at the index in the array.
Here is a good source for sorting an array of dictionaries

NSDictionary filled with JSON data

I call an URL that returns me JSON (I use JSONKit). I convert it to a NSString that is this way:
[{"name":"aaaaaa","id":41},{"name":"as","id":23},...
And so on. I want to fill an UIPickerView with only the "name" part of the JSON. But, when the user selects a name, i need the "id" parameter, so i've thought to fill a NSDictionary with the JSON (setValue:id for key:name), so i can get the value picked by the user, and get the id from the dictionary. how could I fill an array with only the "name" of the JSON?
Im a bit lost with the JSONKit library, any guidance? Thank you.
First of all I don't think that its a good idea to have name as key in a dictionary, since you can have many identical names. I would go for id as key.
Now, what you could do is:
NSString *myJson; //Suppose that this is the json you have fetched from the url
id jsonObject = [myJson objectFromJSONString];
// Now you have an array of dictionaries
// each one having 2 key/value pairs (name/id)
NSArray *names = [jsonObject valueForKeyPath:#"name"];
NSArray *ids = [jsonObject valueForKeyPath:#"id"];
// Now you have two parallel arrays with names / ids
Or you could just iterate your json object and handle the data yourself:
for (id obj in jsonObject)
{
NSString *name = [obj valueForKey:#"name"];
NSNumber *id = [obj valueForKey:#"id"];
// Do whatever you like with these
}

Resources