I am trying to consume a simple web api that returns the data below in Objective C using AFJSONRequestOperation.
Results; (
{
Category = Groceries;
Id = 1;
Name = "Tomato Soup";
Price = 1;
},
{
Category = Toys;
Id = 2;
Name = "Yo-yo";
Price = "3.75";
},
{
Category = Hardware;
Id = 3;
Name = Hammer;
Price = "16.99";
}
)
My Objective-C call looks like this:
//not the real URL, just put in to show the variable being set
NSURL *url = [NSURL URLWithString:#"http://someapi"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation;
operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
success: ^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"Results; %#", JSON);
self.resultsArray= [JSON objectForKey:#"Results"];
}
failure: ^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error ,id JSON) {
//http status code
NSLog(#"Received Error: %d", response.statusCode);
NSLog(#"Error is: %#", error);
}
];
//run service
[operation start];
When I run my code, I can see the data returned in the NSLog statement. However I get the following error when I try to set the results to my array using the JSON objectForKey statement.
-[__NSCFArray objectForKey:]: unrecognized selector sent to instance 0xe466510
2013-09-30 20:49:03.893 ITPMessageViewer[97459:a0b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFArray objectForKey:]: unrecognized selector sent to instance 0xe466510'
I'm fairly new to Objective-C, and can't figure out why this isn't working. Any help or ideas would be appreciated.
The result you are getting is an Array
objectForKey: is a NSDictionary method
So use valueForKey: which is a NSArray method.
self.resultsArray= [JSON valueForKey:#"Results"];
In your code, the JSON ( result ) need to follow this method to use :
self.resultsArray = (NSArray *)JSON;
It'll force the " id " type to NSArray for your self.resultsArray type ( It is an NSArray, right ? ), then you can use this method to enumerate it.
[self.resultsArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop)
{
NSDictionary *_eachResult = (NSDictionary *)obj;
[_eachResult objectForKey:#"Category"];
//...
}];
Hope it can help you.
I managed to update my web service to return data in a format that the AFJSONRequestOperation was happy with. This allowed me to get the JSON to parse properly. Still not sure why it needed this dictionary combo, but glad it worked.
In case anyone is writing a web api in C# to talk to objective C, this is what I did:
The update was to return the following object as JSON (code is in C#).
Dictionary > with string = "results" and the IEnumerable is my strongly typed array of objects.
public Dictionary<string, IEnumerable<Product>> GetAllProducts()
{
var sortedProuct = results.OrderBy(a => a.Category);
var proddict = new Dictionary<string, IEnumerable<Product>>()
{
{ "results", results},
};
return proddict;
}
this translates to:
Results; {
results = ({
Category = Groceries;
Id = 1;
Name = "Tomato Soup";
Price = 1;},
....
Related
I hint error as below when i pass in data into PushNotificationManager.
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSSingleObjectArrayI un_stringWithMaxLength:]: unrecognized selector sent to instance 0x604000018550'
Here is my code:-
[self.manager GET:#"http://api.xxxx.com/api/promotion/1" parameters:nil progress:nil success:^(NSURLSessionDataTask *task, id responseObject) {
json_promotion = responseObject;
[[UNUserNotificationCenter currentNotificationCenter] setDelegate:self];
NSString *strProTitle = [json_promotion valueForKey:#"title"];
NSLog(#"strProTitle - %#",strProTitle);
//Will get string "Promotion Today!" which is CORRECT
//If i put NSString *strProTitle = #"testing here", error will not appear.
[[PushNotificationManager sharedInstance]graphicsPushNotificationWithTitle:strProTitle subTitle:#"text here" body:#"desc here" identifier:#"2-1" fileName:#"Graphics.jpg" timeInterval:3 repeat:NO];
Any idea? Please help.
Your error message is basically telling you are passing an array instead of string.
I am guessing this is happening becuase valueForKey is returning an array. While parsing an object it's better to type check.
You could instead use json_promotion[0][#"title"].
If you want a better syntax I would use the following
NSString *strProTitle;
if([json_promotion isKindOfClass:[NSArray class]] {
id obj = json_promotion[0][#"title"]
if ([obj isKindOfClass: [NSString class]]) {
strProTitle = obj;
}
}
I know this question has been repeated many times. But I am getting error and I almost tried all answers and solutions.
Here is JSON:
(
{
id = 879453454392996;
name = "Test1 test1";
},
{
id = 139435345344975;
name = "Test2 test2";
}
)
I get this JSON in this way:
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:#"me/friends"
parameters:nil];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error)
{
if (!error) {
NSLog(#"result== %#",result[#"data"]);
}
else
{
NSLog(#"Error in reading friend list");
}
}];
This works fine so far.
Now I want to put these ids inside one array. I have imported:
#import <Foundation/NSJSONSerialization.h>
I am not using any other framework.
EDIT
I tried some of the answers:
NSLog(#"result== %#",result[#"data"]);
Prints:
(
{
id = 879453454392996;
name = "Test1 test1";
},
{
id = 139435345344975;
name = "Test2 test2";
}
)
NSLog(#"name is %#", [result objectForKey:#"name"]);
retun name is (null).
NSLog(#"name is %#", [result[#"data"] objectForKey:#"name"]);
returns:
-[__NSCFArray objectForKey:]: unrecognized selector sent to instance 0x17426d480
2015-09-23 15:11:35.281 myapp[1257:181878] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFArray objectForKey:]: unrecognized selector sent to instance 0x17426d480'
Edit 2
OUTPUT FOR:
NSLog(#"result== %#",result);
result== {
data = (
{
id = 8795555555792996;
name = "TEST TEST";
},
{
id = 139051444474975;
name = "TEST2 TEST2";
}
);
paging = {
next = "https://graph.facebook.com/v2.4/743447008322/friends?format=json&access_token=CAAWScq3N1MCOvayeO1ocBVMzK9WiYDDavjb5nOpDnUocpzTEqDCJ2Ew8X3lLopTJ7EuidUNZChTCebTAULnGq2342RNYVcKmnoo43ssJtr6G0TQQLOTs2kkHtKL4yqu4U37GeyygPe1ZBL59I3MiEV6ju8z4bZAMUxudKRhBJFBLRJFBWZBoyHiZAOozE5oZAncZAjXf04dQEW0EZCXTa&limit=25&offset=25&__after_id=enc_AdBepNUFZAj3OmbSQddddUZCzUtPzeDuYZCO33rkZCfAZBqSkBjwrqRgvPhYEkzkVcuWu46NFLSKN5psNNsR5cIAncWg";
};
summary = {
"total_count" = 7;
};
}
You can get id by:
NSArray * arrData = result[#"data"];
for (NSDictionary * dict in arrData)
{
NSString * strID = dict[#"id"];
}
You don't need to parse the response. It's already parsed for you.
I am trying to access keys from a multi NSDictionary.
This is my output from NSLog
Berlijn[23667:60b] data = {
1 = {
data = (
4,
0,
0,
0
);
key = "June 2014";
};
}
When I try to loop through this dictionary and log the key I get NSInvalidArgumentException because key is a NSString.
This is my current code:
- (void) updateRating: (int) companyID {
APICaller *api = [[APICaller alloc] init];
[api setUrl:#"http://domain.examle/api/getcompanyhistory.php"];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *parameters = #{
#"token": [[[FBSession activeSession] accessTokenData] accessToken],
#"device_token" : [defaults stringForKey:#"uniqueToken"],
#"companyid" : #(companyID)
};
[api setParameters: parameters];
[api sendPostRequest: ^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"data = %#", responseObject);
for(NSDictionary *contentData in responseObject) {
NSLog(#"contentData = %#", [contentData objectForKey:#"key"]);
}
[self.tableView reloadData];
}: ^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
}
As NSDictionary is a dictionary I don't know why it returns a string.
Update (error message):
2014-06-02 01:41:41.386 Berlijn[23747:60b] -[__NSCFString objectForKey:]: unrecognized selector sent to instance 0x1784253e0
2014-06-02 01:41:41.387 Berlijn[23747:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString objectForKey:]: unrecognized selector sent to instance 0x1784253e0'
*** First throw call stack:
(0x1860a309c 0x192021d78 0x1860a7d14 0x1860a5a7c 0x185fc54ac 0x1000eb8ac 0x1000ea014 0x1925f0420 0x1925f03e0 0x1925f356c 0x186062d64 0x1860610a4 0x185fa1b38 0x18b9c7830 0x188fe00e8 0x1000eaff4 0x19260baa0)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
Just because you call contentData a dictionary does NOT make it one.
Fast enumeration of a dictionary iterates over keys, NOT values. Your key is a string (even though you call it an NSDictionary) and will throw an exception when you try to call objectForKey: on it.
Since responseObject is a dictionary you can iterate over the keys AND values using enumerateKeysAndObjectsUsingBlock:(void (^)(id key, id obj, BOOL *stop)).
Another option is to use fast enumeration correctly like so...
for(NSString *key in responseObject) {
NSLog(#"contentData = %#", [responseObject objectForKey:key]);
}
I'm trying to get the data from a JSON response object in my iOS app after I log in. I keep getting this error though.
Error:
'NSInvalidArgumentException', reason: '-[__NSCFArray objectForKeyedSubscript:]: unrecognized selector sent to instance 0x8fc29b0'
Here is my code for the request, I'm using AFNetworking:
self.operation = [manager GET:urlString parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSDictionary *JSON = (NSDictionary *)responseObject;
NSDictionary *user = JSON[#"user"];
NSString *token = user[#"auth_token"];
NSString *userID = user[#"id"];
// NSString *avatarURL = user[#"avatar_url"];
// weakSelf.credentialStore.avatarURL = avatarURL;
weakSelf.credentialStore.authToken = token;
weakSelf.credentialStore.userId = userID;
weakSelf.credentialStore.username = self.usernameField.text;
weakSelf.credentialStore.password = self.passwordField.text;
[SVProgressHUD dismiss];
[self dismissViewControllerAnimated:YES completion:nil];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (operation.isCancelled) {
return;
}
[SVProgressHUD showErrorWithStatus:#"Login Failed"];
NSLog(#"%#", error);
}];
What the JSON response object looks like logged:
<__NSCFArray 0x8cac0b0>(
{
user = {
"auth_token" = b3a18e0fb278739649a23f0ae325fee1e29fe5d6;
email = "jack#jack.com";
id = 1;
username = jack;
};
}
)
I'm converting the array to a Dictionary using pointers like this:
EDIT: As pointed out in the comments incase anyone else stumbles across this with limited knowledge in iOS. I'm casting here not converting. See the answers for a full explanation.
NSDictionary *JSON = (NSDictionary *)responseObject;
I'm new to iOS, apologies if problem is obvious.
Thanks for any help.
The "conversion" you do is not doing any conversion, it's a cast. This simply tells the compiler to ignore the type it knows for this object and act as if it's the type you pass it.
Looking at the output you have, you don't get a dictionary back, but an array of dictionaries with a single dictionary. To get to the first dictionary you can use this instead of the cast:
NSDictionary *JSON = [responseObject objectAtIndex:0];
Note that since you get your data from a web service, you should probably also check if the contents you get are what you expect.
You say:
I'm converting the array to a Dictionary using pointers like this:
But that is not what you are doing. You are casting it, but the underlying object is still an array.
From the JSON response you can see that those JSON is constructed as an array with a single element which is a dictionary. You can get to the dictionary by calling [responseObject firstObject];. Of course, so that you don't get error going in the other direction, you should check how the input is constructed before calling any array or dictionary specific methods on the response object.
You have to convert your self but do not use casting.
Or, this is the code to detect if a json object is an array or dictionary
NSError *jsonError = nil;
id jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&jsonError];
if ([jsonObject isKindOfClass:[NSArray class]]) {
NSLog(#"its an array!");
NSArray *jsonArray = (NSArray *)jsonObject;
NSLog(#"jsonArray - %#",jsonArray);
}
else {
NSLog(#"its probably a dictionary");
NSDictionary *jsonDictionary = (NSDictionary *)jsonObject;
NSLog(#"jsonDictionary - %#",jsonDictionary);
}
I have a simple NSDictionary that I am trying to populate with data from an external site via JSON that is returned. The JSON that is returned is fine but I am haveing trouble getting actual data for a specific key.
Here is the JSON data printed to the console.
This is my JSON data:
(
{
CategoryID = 12345;
CategoryName = "Baked Goods";
},
{
CategoryID = 12346;
CategoryName = Beverages;
},
{
CategoryID = 12347;
CategoryName = "Dried Goods";
},
{
CategoryID = 12348;
CategoryName = "Frozen Fruit & Vegetables";
},
{
CategoryID = 12349;
CategoryName = Fruit;
},
{
CategoryID = 12340;
CategoryName = "Purees & Soups";
},
{
CategoryID = 12341;
CategoryName = Salad;
},
{
CategoryID = 12342;
CategoryName = "Snack Items";
},
{
CategoryID = 12343;
CategoryName = Vegetables;
}
)
The error I am getting is:
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[__NSCFArray
enumerateKeysAndObjectsUsingBlock:]: unrecognized selector sent to
instance 0x6884000'
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSError *error = nil;
// Get the JSON data from the website
NSDictionary *categories = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
if (categories.count > 0){
NSLog(#"This is my JSON data %#", categories);
[categories enumerateKeysAndObjectsUsingBlock: ^(__strong id key, __strong id obj, BOOL *stop) {
NSLog(#"Key = %#, Object For Key = %#", key, obj); }];
}
I'm not sure why this is happening but I'm sure it's something simple like I am using the incorrect object or something.
Help is appreciated.
+JSONObjectWithData:options:error: is returning an NSArray not an NSDictionary. '-[__NSCFArray enumerateKeysAndObjectsUsingBlock:] is the key part of the error message. It tells you that you are calling -enumerateKeysAndObjectsUsingBlock: on an array.
For this case, you could use -enumerateObjectsUsingBlock: instead.
If you are not sure wether a NSArray or an NSDictionary will be returned, you can use -isKindOf:
id result = [NSJSONSerialization …];
if ([result isKindOf:[NSArray class]]) {
NSArray *categories = result;
// Process the array
} else if ([result isKindOf:[NSDictionary class]]) {
NSDictionary *categories = result;
// Process the dictionary
}
From enumerateObjectsUsingBlock:
Executes a given block using each object in the array, starting with the first object and continuing through the array to the last object.
(void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block
So it should be called as such
[categories enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(#"index = %d, Object For Key = %#", idx, obj);
}];
A quick read of the documentation really can save you lots of frustration.