Error when calling allKeys on NSDictionary containg JSON objects - objective-c

I am working through Apple's sample code for displaying a Twitter feed from here http://bit.ly/x4nhG5
From the example, the code is taking the JSON and putting it into an NSDictionary:
NSDictionary *publicTimeline = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&jsonParsingError];
What I was just trying to do at this point was look at all the keys that came back by doing this:
NSArray *allKeysArray = [publicTimeline allKeys];
I then receive an error while trying to run the program:
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[__NSCFArray allKeys]:
unrecognized selector sent to instance 0x6a950f0'
Any reason why this NSDictionary that is loaded from a JSON is behaving this way?
Thanks,
Flea

If you look at the exception you see '-[__NSCFArray allKeys], this indicates that you actually have an __NSCFArray which is a private subclass of NSArray. This is not an NSDictionary, which is why you get the exception.
If you look at the JSON feed it is of the form
[
{
coordinates: null,
truncated: false,
// ...
},
{
coordinates: null,
truncated: false,
// ...
}
]
In JSON [] represents an array and {} represents an object.
An [JSON] array is an ordered collection of values
This means a JSON array can easily be mapped to an NSArray.
An [JSON] object is an unordered set of name/value pairs
This means a JSON Object can be mapped to an NSDictionary.
So looking at the feed we can see that we actually have an array of objects. Which NSJSONSerialization will turn into an NSArray of NSDictionary's. Therefore to get to a dictionary we first need to access it from the array first resulting in:
NSDictionary *tweet = [publicTimeline objectAtIndex:0];
NSArray *allKeys = [tweet allKeys];

What the error tells you is that your publicTimeline is not NSDictionary but NSArray.
So, my guess is that instead of
NSArray *allKeysArray = [publicTimeline allKeys];
this would work as you intend.
NSArray *allKeysArray = [[publicTimeline objectAtIndex:0] allKeys];

Related

Convert JSON String into NSDictionary with same order [duplicate]

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.

Error trying to separate an array containing managed object context

Could anyone please tell me why I am getting this error and why this code isn't working?
Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[__NSArrayI componentsSeparatedByString:]: unrecognized
selector sent to instance 0x109494750'
This is the code with problems:
NSArray *array = [self.managedObjectContext executeFetchRequest:request error:nil];
NSString *dateString = [array valueForKey:#"dateString"];
NSArray *datesArray = [dateString componentsSeparatedByString:#","];//line with problems
When you call valueForKey: on array the result will be an NSArray containing the result of calling valueForKey: on each of it's elements.
So dateString is not actually a string it's an instance of NSArray, which does not respond to componentsSeparatedByString:. You need to index into the array to get the date you want before calling componentsSeparatedByString: on that
It's an indication that dateString isn't a string. When you call -valueForKey: on an array, it returns an array. Per the docs:
Returns an array containing the results of invoking valueForKey: using key on each of the array's objects.
So you're calling a string method on an array. It's not clear what you're trying to accomplish by calling -valueForKey:. Perhaps you meant -objectAtIndex:?

nsdictionary issue

I have the following data in a NSDictionary Variable:
{
value = "TV-PG";
}
I was wondering how to get the value for key "value" here.
I tried:
NSDictionary *fieldMaturityRating = [[parsedItems objectAtIndex:0] objectForKey:#"field_maturity_rating"];
NSString *dateRelease = [fieldMaturityRating objectForKey:#"value"];
(where, fieldMaturityRating is a NSDictionary with the given value)
and I get:
-[__NSArrayM objectForKey:]: unrecognized selector sent to instance 0xd9cd3f0
[10530:707] *** Terminating app due to uncaught exception: -[__NSArrayM objectForKey:]: unrecognized selector sent to instance 0xd9cd3f0
Can anyone kindly help me ?
Thanks.
Note: if I pause the execution and do a po after the 1st line of code presented here, I get the following:
(gdb) po fieldMaturityRatingNew
<__NSArrayM 0x79af250>(
{
value = "TV-PG";
}
)
The po actually shows your issue:
(gdb) po fieldMaturityRatingNew
<__NSArrayM 0x79af250>(
{
value = "TV-PG";
}
)
The outer ( and ) mean that your object is actually an array.
Inside that is where the { and } denote your dictionary.
So you really want:
NSString *value = [[fieldMaturityRatingNew objectAtIndex:0] objectForKey:#"value"];
You're actually sending that NSDictionary message to a NSMutableArray instance.
You might want to check your code again as the objectForKey: method is right when pointing to a NSDictionary.
This means your fieldMaturityRating is not actually an NSDictionary. Make sure you aren't setting it to an array somewhere in your code.
Edit:
This means your fieldMaturityRating is actually an NSArray containing an NSDictionary. If this is your intended data structure then you can access your value like so.
NSString *dateRelease = [[fieldMaturityRating objectAtIndex:0] objectForKey:#"value"];
I don't believe this is your intended data structure so you should look into why your parsedItems array returned you an NSArray instead of an NSDictionary. If you track this problem down you can stop any headaches in the future.
Based on your datastructure which is a dictionary inside an array, dateRelease should be like this
NSString *dateRelease = fieldMaturityRating[0][#"value"];

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]);
}