Getting "unrecognized selector sent to instance" in code for ios8 - objective-c

This code work in ios7, but I am now getting the error :
-[__NSCFString objectForKeyedSubscript:]: unrecognized selector sent to instance
.m file
//get the JSON response
NSDictionary *jsonData = [NSJSONSerialization
JSONObjectWithData:urlData
options:NSJSONReadingMutableContainers
error:&error];
//Parses the "success" value
success = [jsonData[#"success"] integerValue];
//Was it successful?
if(success){
//successful, save the profile gathered into global gMyProfile
NSArray *profileJSON=jsonData[#"myProfile"];
for (NSDictionary* dict in profileJSON)
{
NSLog(#"First_Name: %#", dict [#"first_name"]);
...
The error is happening on the NSLog statement and from a little research it is complaining about the dict[#"first_name"]);
login.py
....
#Query for user
db_cursor = db.cursor(MySQLdb.cursors.DictCursor)
db_query = """SELECT users.email, users.first_name, users.profile_pic_path, \
FROM users,data WHERE users.email='%s' \
AND users.user_id=data.user_id""" % user_email
db_cursor.execute(db_query)
#If there is one record containing the username check password
if(db_cursor.rowcount == 1):
user_profile = db_cursor.fetchone()
...
json_obj= {'success': 1, 'myProfile': user_profile,}
...
JSON Output:
{'myProfile': {'first_name': 'Matt', 'email': 'matt#email.com', 'profile_pic_path': 'default'}, 'success': 1}
All this code was working, I have not changed anything.
Any help will be greatly appreciated!!!!

dict is not a dictionary. It is a string. Print it and you'll know which string it is.
More likely than not, your JSON is not what you think it is. In particular, the myProfile value is a string instead of a dictionary.
What happens if fetchone() returns None; do you end up with a string in your JSON?

Changed in the .m
//Was it successful?
if(success){
//successful, save the profile gathered into global gMyProfile
NSArray *profileJSON=jsonData[#"myProfile"];
for (NSDictionary* dict in profileJSON)
{
...
to
//Was it successful?
if(success){
//successful, save the profile gathered into global gMyProfile
NSDictionary* dict=jsonData[#"myProfile"];
//no more for loop
...
The python JSON module returns a single dictionary instead of an array of a single dictionary when there is one element. If there are multiple it returns an array of dictionaries.
Still don't know why this didn't give me trouble in ios7 but did in ios8.

Related

Access string in a dictionary (Objective-c)

I am having a ton of trouble accessing a string in a dictionary, called json. This comes back from a server in an API call. The key that I am trying to access is "Message".
Some reason the console shows that I am retrieving a dictionary in "Errors", but when I try to access this value the app crashes.
How do I appropriately get and store the key "Message" and the value " The old password does that match our records"?
CODE:
//json is the dictionary I successfully retrieve from an API call (see picture)
DLog(#"feed response = %#", json);
NSDictionary *errorsDictionary;
//CRASHES ON THE NEXT LINE
errorsDictionary = [[NSDictionary alloc]initWithDictionary:[json objectForKey:#"Errors"]] ;
NSString *message = [[NSString alloc]initWithFormat:#"%#",[errorsDictionary objectForKey:#"Message"]];
NSLog(#"The dictionary is%#", errorsDictionary);
Console log:
Errors contains an array, the message is the value for key Message of the first item.
NSString *message = json[#"Errors"][0][#"Message"];
NSLog(#"The message is %#", message);

How to handle JSON exception objective c

Before I make url, which I will use to fetch json, user has to input some data first.
If the input data is wrong, the JSON will not be fetched properly.
But I cannot figure out how to handle that exception of calling JSON with wrong url.
this is my code:
NSError *error;
NSMutableDictionary* json = [NSJSONSerialization
JSONObjectWithData:url
options:NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves
error:&error];
if (error){
NSLog(#"%#",[error localizedDescription]);
}
else{
#try {
if (json){
[Constants shared].salt = json[#"salt"];
The last line of code is where the exception occurs, since the user had put the wrong input.
SO obviously, there wont be a proper json response fetchet, and there will be no "salt" object.
Error I get is:
-[__NSArrayM objectForKeyedSubscript:]: unrecognized selector sent to instance 0x146aa310
I tried putting json fetching in #try #catch, but it didn't work out.
Any suggestions ?
EDIT:
this is the json responce I get, when the user types in the right code:
{
user_id: "22066",
salt: "ce8c0f9e3e1add06bebc1acded7b692b68efddb87bfdc5bb1fb516f6a3e24425"
}
This is what i get, when the code is invalid:
[ ] (empty array)
The problem isn't that the dictionary lacks an object for the key #"salt", it's that json isn't a dictionary in the first place. Take a close look at the error message and you'll see that it's an array. The problem isn't the key, but the fact that arrays don't respond to -objectForKeyedSubscript:.
Accordingly, when you get an object back from -JSONObjectWithData:..., check that it's not nil and that it is in fact a dictionary before you try to access its contents. You can check it like this:
if ([json isKindOfClass:[NSDictionary class]]) {
// put the code that accesses `json` here
}
That condition will be false if json is nil or something other than a dictionary. You could add an else clause to take any necessary steps to recover if you're relying on getting the data.

Parse JSON String and array with NSJSONSerialization issue?

This is the code i have so far
// Parse data using NSJSONSerialization
NSError *error = nil;
NSArray *JsonArray = [NSJSONSerialization JSONObjectWithData:myData options:NSJSONReadingMutableContainers error: &error];
if(!JsonArray)
{
NSLog(#"Error Parsing Data: %#", error);
}
else
{
for(NSDictionary *event in JsonArray)
{
if([[event description] isEqualToString:#"error"])
{
// Get error number? I am confused by this part
NSLog(#"Element: %#", [event objectForKey:#"error"]);
}
else
{
NSLog(#"Element: %#", [event description]);
}
}
}
this is the JSON Data that parses correctly:
[{data string}, {data strings}]
This only gives me the string "error" and not the int as well:
{"error":0}
I am echoing this data from a PHP script if that helps any. Am i just doing it wrong, or did i miss something?
Your problem is that when you receive an error, you get back an NSDictionary and not an NSArray. This should work:
if ([jsonObject isKindOfClass:[NSArray class]]) {
// no error: enumerate objects as you described above
} else if ([jsonObject isKindOfClass:[NSDictionary class]]) {
// error: obtain error code
NSNumber *errCode = jsonObject[#"error"];
} else {
// something bad's happening
}
Stylistic pieces of advice:
Don't call your object JsonArray, since it's not always an array. Call it jsonObject.
Don't start variable names with capital letters.
Would be great if you had posted the complete JSON document that you are trying to parse, because without that, there is absolutely no chance to figure out whether your code is anywhere near correct. The example [{data string}, {data strings}] that you gave is most definitely not a correct JSON document, so trying to parse it will return nil. {"error":0} is a dictionary with a single key "error" and a value 0. Having dictionaries with a single key is let's say unusual.
A JSON document contains either an array or object (using JSON terms) which will be turned either into an NSArray* or an NSDictionary*. You should know whether you expect an array or dictionary. If you expect an NSArray, check that [jsonObject isKindOfClass:[NSArray class]]. If you expect an NSDictionary, check that [jsonObject isKindOfClass:[NSDictionary class]]. If you don't do that then the wrong JSON document will either crash your app or produce total nonsense.
If you have an array then you will usually iterate through the elements of the array and handle each one in turn. If you have a dictionary you will usually look up keys that you know how to handle. What you are doing, iterating through an array of dictionaries, and checking for a dictionary with a key of "error", that's a very strange design of your JSON document.
And lookup what the "description" method does. "description" is what NSLog calls to find out what to print when it is asked to print an object. For an NSDictionary with a single key "error" and a value 0, it would return something like "error:0" which is of course not the same as "error".
NSDictionary *jsonDic = [NSJSONSerialization JSONObjectWithData:myData options:NSJSONReadingMutableContainers error:&error];
NSLog(#"jsonDic: %#", [jsonDic objectForKey:#"string"]);

Exception when trying to fetch channelId using the youtube api in objective c

I am trying to fetch youtube channel id using the google-api-objectivec-client. The problem I am having is basically that for some reason I am receiving exception when trying to access the channelId. The code I am using:
GTLServiceYouTube *service = [[GTLServiceYouTube alloc] init];
service.APIKey = _MY_API_KEY_;
GTLQueryYouTube *query = [GTLQueryYouTube queryForSearchListWithPart:#"id"];
query.q = #"google";
query.type = #"channel";
query.maxResults = 1;
GTLServiceTicket *ticket = [service executeQuery:query completionHandler:^(GTLServiceTicket *ticket, id object, NSError *error) {
if (error == nil) {
GTLYouTubeSearchListResponse *products = object;
for (id item in products.items) {
GTLYouTubeSearchResult *result = item;
NSLog(#"Identifier:%#",result.identifier);
GTLYouTubeResourceId* resourceId = result.identifier;
NSLog(#"kind:%#",resourceId.kind);
NSLog(#"channel:%#",resourceId.channelId);
}
}else{
NSLog(#"Error: %#", error.description);
}
}];
The output I get when i am running this code is:
2013-04-05 11:37:12.615 YouTest[21704:11303] Identifier:GTLYouTubeChannel 0x7233b00: {kind:"youtube#channel" channelId?:"UCK8sQmJBp8GCxrOtXWBpyEA"}
2013-04-05 11:37:12.617 YouTest[21704:11303] kind:youtube#channel
2013-04-05 11:37:12.617 YouTest[21704:11303] -[GTLYouTubeChannel channelId]: unrecognized selector sent to instance 0x7233b00
2013-04-05 11:37:12.618 YouTest[21704:11303] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[GTLYouTubeChannel channelId]: unrecognized selector sent to instance 0x7233b00'
So my implementation crashes on the point where I am trying to access the channelId of the resourceId. From the documentation I understood that the channelId should be there as the type of the resourceId is youtube#channel. The channelId can be off course parsed from the result.identifier string that I am also printing, but since there is a property for the channelId I would prefer using that.
Any ideas about what is wrong with my code?
There is indeed a bug in the Google libraries. However I solved this problem by accessing the JSON string directly and parsing it with the help of the NSString+SBJSON.h class, as in this example.
#import "NSString+SBJSON.h"
...
GTLYouTubeResourceId *resource = channel.snippet.resourceId;
NSDictionary *jsonObject = [resource.JSONString JSONValue];
NSString *channelid = [jsonObject valueForKey:#"channelId"];
I'm not very familiar with Objective-C, but yeah, that looks like there's something wrong with the generated client library's YouTube Data API v3 bindings. Are you using the latest version from the project page? You might want to file a bug against the client library if you can reproduce it with the latest version. While troubleshooting this further, I'd check to see if you have the same problem when query.type = #"video"; and you try to access the videoId of the response item.
Here's an alternative you could try, though. The channel's id is also returned in the snippet.channelId property. If you request the snippet part via GTLQueryYouTube *query = [GTLQueryYouTube queryForSearchListWithPart:#"snippet"]; see if you can read that value instead.
I had the same issue. Solved it with the following...
NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:[resourceId.JSONString dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
NSString *channelId = [jsonObject valueForKey:#"channelId"];
NSLog(#"channelId is %#", channelId);
Workaround Code:
channel.snippet.resourceId.JSON[#"channelId"];
No need to parse the JSON yourself as the underlying JSON is exposed.
It looks like the automatic binding is not working for GTLYouTubeResourceId because the "kind" element of "youtube#channel" is throwing off the runtime object creation and creating a GTLYouTubeChannel instead.
Thorough Workaround Code:
ticket.surrogates = #{ (id)[GTLYouTubeChannel class] : [GTLYouTubeResourceId class] };
If you really want to force that binding to work you can workaround a little further upstream on the ticket when you execute the query.
Global Workaround Patch:
https://github.com/google/google-api-objectivec-client/pull/109
There's open tickets for the issue:
https://github.com/google/google-api-objectivec-client/issues/63
https://github.com/google/google-api-objectivec-client/issues/92
It seems they want to change the API to not call the resourceId.kind 'kind' to avoid this problem. But while we wait for the API to change, any of these three workarounds should serve your purposes.

Xcode json error

I'm learning Xcode at the moment and i have a project that is pulling data from a Mysql database using php and passing it to my app via json. In the database all varchars are set to utf8_bin.
here is the php:
header('Cache-Control: no-cache, must-revalidate');
header('Content-type: application/json');
echo json_encode($this->Idea_model->get($id));
here is a snipet of the outputted JSON:
[{"id":"1","title":"JWT blood sucka","objective":"test ","mission":"test","design_time":"80","development_time":"80","votes":"0","user_id":"0","date_created":"2012-08-03","date_modified":"2012-08-03","active":"1"},{"id":"2","title":"ford - liveDealer","objective":"to increce ","mission":"thid id a es","design_time":"80","development_time":"80","votes":"1","user_id":"1","date_created":"0000-00-00","date_modified":"0000-00-00","active":"1"}]
in xcode I'm using this function to pull in the JSON [reference tutorial:
http://www.raywenderlich.com/5492/working-with-json-in-ios-5]
(void)fetchedData:(NSData *)responseData {
//parse out the json data
NSError* error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:responseData //1
options:kNilOptions
error:&error];
NSArray* latestLoans = [json objectForKey:#"loans"]; //2
NSLog(#"loans: %#", latestLoans); //3
}
when i use this JSON file from the tutorial it works
http://api.kivaws.org/v1/loans/search.json?status=fundraising
but when i use my JSON file i get the following error.
[8690:207] -[__NSCFArray objectForKey:]: unrecognized selector sent to instance 0x6a10400
Current language: auto; currently objective-c
obviously there is an issue with my JSON output as i printed the contents from the tutorial file in my PHP file and that worked as well.
i also have tried "reset contents and settings" in the iOS simulator.
any ideas?
The returned object appears to be an array but your code is treating it like a dictionary (json object/hash)
The error tells you this: it say that the message objectForKey: (which is a method on NSDictionary) is being sent to an instance of __NSCFArray, which is an implementation class of NSArray, hence my supposition...
Yes I have an Idea -
-[__NSCFArray objectForKey:]: unrecognized selector sent to instance 0x6a10400
Arrays are not dictionaries. They do not respond to objectForKey
They respond to objectForIndex;
You are thinking you have an array when you have a dictionary.
Common JSON mistake.
Heres your data:
its a list
starts here --> "[" then the object starts here "{"
[{"id":"1","title":"JWT blood sucka","objective":"test ","mission":"test","design_time":"80","development_time":"80","votes":"0","user_id":"0","date_created":"2012-08-03","date_modified":"2012-08-03","active":"1"}
then a comma "," then the next item in the list starting with a { "{"id":"2","title":"ford - liveDea
JSON says a list is an array and an object is a dictionary so flip your code around
(void)fetchedData:(NSData *)responseData {
//parse out the json data
NSError* error;
NSArray* latestLoans = [NSJSONSerialization
JSONObjectWithData:responseData //1
options:kNilOptions
error:&error];
NSLog(#"loans: %#", latestLoans); //3
for (int i=0; i < latestLoans.count; i++)
{
NSDictionary *myLoan = (NSDictionary*)[latestLoans objectAtIndex:i];
NSLog(#"loan:%#", myLoan);
}
....
Got it?