iOS App crashes showing Variable is not a CFArray - iphone

I am using the below code to retrieve data from web services coming in JSON format
NSString *responseString = [request responseString];
NSDictionary *responseDict = [responseString JSONValue];
NSMutableDictionary *statusDict = [responseDict objectForKey:#"body"];
NSArray *arrayPickListValue = [statusDict objectForKey:#"ticketEntries"];
sometimes data is coming in arrayPickListValue and showing the content on iPhone, however sometimes if ticketEntries key is Null , it is showing Variable is not a CFArray, so how do i solve with this issues

As #Beppe said, you need to check it first:
// check whether it is NULL or not first
id arrayPickListValue = [statusDict objectForKey:#"ticketEntries"];
if ([arrayPickListValue isKindOfClass:[NSNull class]]) {
// manage the error
return;
}
// do work

Try this:
if([[statusDict objectForKey:#"ticketEntries"] isKindOfClass:[NSArray class]])
{
//is array
NSArray *arrayPickListValue = [statusDict objectForKey:#"ticketEntries"];
}
else
{
//not a array
//manage here as it might is null.
}

Related

Consuming complex JSON API responses into NSObjects using NSKeyValueCoding

The blog post SAVING JSON TO CORE DATA has some great tips for converting a JSON response into a Core Data entity. What I want to do is a little bit more specific. I'd like to take a JSON response and convert the objects using the methods in the blog post into an NSObject with properties representing the response objects. The problem that I'm running into are nested properties of the object. Take this JSON response as an example:
http://us.battle.net/api/d3/profile/rnystrom-1254/
Using the methods described in the blog post, simple properties like "name" and "level" are easy to convert to NSString and NSNumber objects. However the problem arises when looking at more complex parts of the response: nested arrays/dictionaries.
The only solution I've found is to hand-code the finding and converting of all of these properties which I feel is a really poor practice. Here's an excerpt of what I'm doing:
NSDictionary *skillsDictionary = json[#"skills"];
if ([skillsDictionary isKindOfClass:[NSDictionary class]]) {
NSArray *activeArray = skillsDictionary[#"active"];
NSArray *passiveArray = skillsDictionary[#"passive"];
NSMutableArray *mutActives = [NSMutableArray array];
NSMutableArray *mutPassives = [NSMutableArray array];
if ([activeArray isKindOfClass:[NSArray class]]) {
[activeArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj isKindOfClass:[NSDictionary class]]) {
NSDictionary *activeJSON = (NSDictionary*)obj;
D3Skill *skill = [D3Skill activeSkillFromJSON:activeJSON];
if (skill) {
[mutActives addObject:skill];
}
}
}];
}
if ([passiveArray isKindOfClass:[NSArray class]]) {
[passiveArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj isKindOfClass:[NSDictionary class]]) {
NSDictionary *passiveJSON = (NSDictionary*)obj;
D3Skill *skill = [D3Skill passiveSkillFromJSON:passiveJSON];
if (skill) {
[mutPassives addObject:skill];
}
}
}];
}
self.activeSkills = mutActives;
self.passiveSkills = mutPassives;
}
I use the SBJSON library and ASIHttpRequest to fetch and consume JSONs from a webservice of my own design, if I understand your question correctly, you'd just need to do something like this:
NSString *responseJSONasString = [fetchRequest responseString];
NSDictionary *itemResponseArray = [responseJSONasString JSONValue];
The SBJSON library will do the converting for you into NSObjects and put them into Arrays/Dictionaries using key:value coding on the JSON elements, so with the JSON you provided I could get the first hero's name with:
NSArray *heroes = [itemResponseArray objectForKey:#"heroes"];
NSDictionary *firstHero = [heroes objectAtIndex:0];
NSString *heroName = [firstHero objectForKey:"name"];
SBJson can be found here: http://stig.github.com/json-framework/
BWJSONMatcher is a lightweight library i used in my projects to convert JSON data from RESTful api to my business data model. And it goes like this:
...
NSString *jsonString = #"{your-json-string}";
YourValueObject *dataModel = [YourValueObject fromJSONString:jsonString];
NSDictionary *jsonObject = #{your-json-object};
YourValueObject *dataModel = [YourValueObject fromJSONObject:jsonObject];
...
YourValueObject *dataModel = instance-of-your-value-object;
NSString *jsonString = [dataModel toJSONString];
NSDictionary *jsonObject = [dataModel toJSONObject];
...

How to parse the JSON response?

I am working on a project where the facebook's friend list have to de displayed. I did all necessary coding to get the reponse , but the reponse is like the following
{"data":[{"name":"Ramprasad Santhanam","id":"586416887"},{"name":"Karthik Bhupathy","id":"596843887"},{"name":"Anyembe Chris","id":"647842280"},{"name":"Giri Prasath","id":"647904394"},{"name":"Sadeeshkumar Sengottaiyan","id":"648524395"},{"name":"Thirunavukkarasu Sadaiyappan","id":"648549825"},{"name":"Jeethendra Kumar","id":"650004234"},{"name":"Chandra Sekhar","id":"652259595"}
Can anyone please tell me how to save name and id in two different arrays.
Any help will be appreciated.
you can see below how html response parse . there i am getting facebook friends.
- (void)fbGraphCallback:(id)sender
{
if ( (fbGraph.accessToken == nil) || ([fbGraph.accessToken length] == 0) )
{
//restart the authentication process.....
[fbGraph authenticateUserWithCallbackObject:self andSelector:#selector(fbGraphCallback:)
andExtendedPermissions:#"user_photos,user_videos,publish_stream,offline_access,user_checkins,friends_checkins"];
}
else
{
NSLog(#"------------>CONGRATULATIONS<------------, You're logged into Facebook... Your oAuth token is: %#", fbGraph.accessToken);
FbGraphResponse *fb_graph_response = [fbGraph doGraphGet:#"me/friends" withGetVars:nil];// me/feed
//parse our json
SBJSON *parser = [[SBJSON alloc] init];
NSDictionary * facebook_response = [parser objectWithString:fb_graph_response.htmlResponse error:nil];
//init array
NSMutableArray * feed = (NSMutableArray *) [facebook_response objectForKey:#"data"];
// NSMutableArray *recentFriends = [[NSMutableArray alloc] init];
arr=[[NSMutableArray alloc]init];
//adding values to array
for (NSDictionary *d in feed)
{
[arr addObject:d];
}
//NSLog(#"array is %# ",arr);
[fbSpinner stopAnimating];
[fbSpinner removeFromSuperview];
[myTableView reloadData];
}
}
This is json response you are getting. So you need a JSON parser to convert this string into Objective-C objects. In iOS App, you can use a library like the json-framework. This library will allow you to easily parse JSON and generate json from dictionaries / arrays (that's really all JSON is composed of).
From SBJson docs: After JSON parsing you will get this conversion
JSON is mapped to Objective-C types in the following way:
null -> NSNull
string -> NSString
array -> NSMutableArray
object -> NSMutableDictionary
true -> NSNumber's -numberWithBool:YES
false -> NSNumber's -numberWithBool:NO
integer up to 19 digits -> NSNumber's -numberWithLongLong:
all other numbers -> NSDecimalNumber
That looks like JSON, not HTML. (You probably already knew this, since you tagged the question with json I see.)
I'm not really sure why others are recommending third-party libraries to do this, unless you need to support rather old OS releases. Just use Apple's built-in NSJSONSerialization
class.
This is not HTML. This is JSON. You'll need a JSON parser for this.
A JSON parser would typically make an NSDictionary or NSArray out of the string. With my implementation, you'd do something like this:
NSMutableArray *names = [NSMutableArray array];
NSMutableArray *ids = [NSMutableArray array];
NSDictionary *root = [responseString parseJson];
NSArray *data = [root objectForKey:#"data"];
for (NSDictionary *pair in data)
{
[names addObject:[pair objectForKey:#"name"]];
[ids addObject:[pair objectForKey/#"id"]];
}
Recent versions of iOS contain a new Foundation class, NSJSONSerialization, that will handle any JSON parsing and serialization for you.

working with json data

I have the follow code that parses JSON data received from a server:
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
NSArray *array_webdata=[[NSArray array] init];
NSString *searchStatus = [[NSString alloc] initWithData:webData encoding:NSUTF8StringEncoding];
array_webdata = [parsedata objectWithString:searchStatus error:nil];
NSDictionary *usersList = [array_webdata valueForKey:#"results"];
//I think that is not a real NSDictionary because if I write NSArray *keys = [usersList allKeys]; the execution crashes
NSLog(#"\n usersList =\n %# \n", usersList);
[searchStatus release];
[connection release];
[webData release];
[pool drain];}
the json data stored in usersList has the structure:
(
{
createTime = "date hour";
fullname = "user name";
"prof_id" = number;
thumb = "image.jpg";
},
{
data of rest of users...
}
)
And I would like create a class to store the data of each user and use "prof_id" when I want to use a particular use.
I need this because the app needs a list with all users (not tableview) and I think this is de easiest way.
Can someone help me? Thanks!!
Please used JsonKit Framework to parse json data received from web service.
Read data and parse using JSONKit:
NSData* jsonData = [NSData dataWithData:webData];
JSONDecoder* decoder = [[JSONDecoder alloc]
initWithParseOptions:JKParseOptionNone];
NSArray* json = [decoder objectWithData:jsonData];
After that, you'll have to iterate over the json variable using a for loop.
Create new class with the name User (file->new->file) inherited from NSObject class, create required parameters in .h/.m file.(do synthesize to generate getter/setter for attributes)
import User.h in your connection class and create objects of User entity in iterator loop and add those object in global scope array.
for(NSDictionary *userInfo in json) {
User* user=[[User alloc] init];
user.fullName=[userInfo valueForKey:#"fullname"];
user.prof_id=[[userInfo valueForKey:#"prof_id"] integerValue];
// Add into your global array
[usersList addObject:user];
[user release];// if ARC is not enable
}
// Check for successful object creation
NSLog(#"USER LIST contain User class Objects- %#",userList);
if i'm not wrong the only thing you need to do is :
NSMutableArray *yourArray = usersList;
and then with a for loop like
for(int i = 0;i<[usersList count] ;i++)
{
NSMutableDictionary *yourDictionary = [usersList objectAtIndex:i];
int prof_id = [yourDictionary valueForKey:#"prof_id"];
}
you can get your prof_id like that.
i hope this helps...
Use JSON Framework, and parse data using below code.
NSString* newStr = [[NSString alloc] initWithContentsOfURL:[NSURL URLWithString:#"yout link to json file"] encoding:NSUTF8StringEncoding error:nil];
NSLog(#"new str - %#",newStr);
NSArray *response = [newStr JSONValue];
NSLog(#"json array - %#",response);
Use the response array to show your results.

How to extract the actual NSString from json object as NSArray

I'm working with a large set of json and really just need the NSString representation of what's inside the NSArray -including all the { }
My question is this - is their a better way than simply looping through each NSArray inside the main NSArray and outputting the description one by one?
ie- the below is a start to this process but it's very brittle meaning I need to know each item inside the hat {} and this isn't something I actually care about. I just need the json string to move forward.
The working code is below (thank you in advance!)
NSString* responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
NSArray* json = [responseString JSONValue];
NSArray* item = [json valueForKeyPath:#"d.data"];
NSArray* hatjson = [item objectForKey:#"hat"];
NSMutableString * result = [[NSMutableString alloc] init];
for (NSObject * obj in hatjson)
{
[result appendString:[obj description]];
}
NSLog(#"the hat json is .. %#", result);
// …
NSArray* hatjson = [item objectForKey:#"hat"];
NSString *result = [hatjson JSONRepresentation];
NSLog(#"the hat json is .. %#", result);
I’m assuming you’re using SBJSON for JSON parsing. SBJSON defines a category on NSObject that includes the method
- (NSString *)JSONRepresentation;
This method returns a string with the JSON representation of a given object so long as the object is an instance of a class which SBJSON can convert to JSON (e.g. strings, numbers, arrays, dictionaries).
I'm assuming you're using the JSON library from here: https://github.com/stig/json-framework
You're complaining that the code you provided is brittle, but it sounds like, for what you want, the situation is brittle, so I think it's ok for the code that access it to be brittle, as long as you put NSAsserts in there so that you know ASAP when your assumptions have been broken.
I think the most brittle aspect of the code you've shown is that it assumes you're getting back NSArrays, when it appears from how you're accessing it that it's actually giving you NSDictionaries.
For instance, reading your code, I conclude that the responseString represents a JSON nested map looking something like this:
{ "d": { "data": { "hat": "baseball cap" } } }
The question then is "do you ever expect the value corresponding to the "hat" key to ever have more than one value?" I would genericize this code like so:
NSString* responseString = [[[NSString alloc] initWithData: responseData encoding: NSUTF8StringEncoding] autorelease];
[responseData release];
id json = [responseString JSONValue];
id hatJSONValue = [json valueForKeyPath:#"d.data.hat"];
NSString* result = nil;
if ([hatJSONValue isKindOfClass: [NSArray class]] && [hatJSONValue count] == 1)
{
result = [[hatJSONValue lastObject] description];
}
else
{
NSAssert(NO, #"Assumptions about returned JSON were wrong.");
}
NSLog(#"the hat json is .. %#", result);
Generally speaking, you always have to make tradeoffs between writing non-brittle code and getting things done. The key should be that if your code is going to make assumptions, you should assert that they're true, so if the situation ever changes, you'll know!

Moving through JSON data in iPhone app

I'm afraid I'm a newbie to objective-c programming, and I am having a problem that I have spent all day trying to figure out and I cannot, so I am humbly asking you guys if anyone can help.
I am trying to read the details from a JSON page online (for instance a local services directory) and have installed the JSON library into Xcode and it seems to work fine. I'm developing for the iPhone by the way, and have the latest versions all installed.
The problem is, what with me being a newb and all, I seem unable to retrieve all the information I need from the JSON file.
the JSON data I am testing with is this:
"testlocal_response" = {
header = {
query = {
business = newsagent;
location = brighton;
page = 1;
"per_page" = 1;
"query_path" = "business/index";
};
status = ok;
};
records = (
{
address1 = "749 Rwlqsmuwgj Jcyv";
address2 = "<null>";
"average_rating" = 0;
"business_id" = 4361366;
"business_keywords" = "<null>";
"business_name" = "Gloucester Newsagents";
"data_provider_id" = "<null>";
"display_details" = "<null>";
"distance_in_miles" = "0.08";
fax = "<null>";
gridx = "169026.3";
gridy = "643455.7";
"image_url" = "<null>";
latitude = "50.82718";
"logo_path" = Deprecated;
longitude = "-0.13963";
phone = 97204438976;
postcode = "IY1 6CC";
"reviews_count" = 0;
"short_description" = "<null>";
"touch_url" = "http://www.test.com/business/list/bid/4361366";
town = BRIGHTON;
url = "<null>";
}
);
};
}
Now, in my code ViewController.m page, in the 'connectionDidFinishLoading' area I have added:
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
// make sure JSON has all been pulled in
NSLog(#"This is from the JSON page:\n");
NSLog(responseString);
NSError *error;
SBJSON *json = [[SBJSON new] autorelease];
// using either of these seems to make no difference?
NSDictionary *touchDirect = [json objectWithString:responseString error:&error];
//NSArray *touchDirect = [json objectWithString:responseString error:&error];
[responseString release];
if (touchDirect == nil)
label.text = [NSString stringWithFormat:#"JSON parsing failed: %#", [error localizedDescription]];
else {
NSMutableString *text = [NSMutableString stringWithString:#"Test directory details:\n"];
[text appendFormat:#"%#\n", [[[[touchDirect objectForKey:#"testlocal_response"] objectForKey:#"header"] objectForKey:#"query"] objectForKey:#"business"]];
label.text = text;
Testing this I get the value for the business ('newsagent') returned, or location ('brighton') which is the correct. My problem is, I cannot go further into the JSON. I don't know how to pull out the result for the actual 'records' which, in the test example there is only one of but can be more divided using brackets '(' and ')'.
As soon as I try to access the data in these record areas (such as 'address1' or 'latitude' or 'postcode') it fails and tells me 'unrecognized selector sent to instance'
PLEASE can anyone tell me what I'm doing wrong?! I've tried so many different things and just cant get any further! I've read all sorts of different things online but nothing seems to help me.
Any replies deeply appreciated. I posted up a question on iPhone SDK too but havent had a useful response yet.
many thanks,
-Robsa
Have you validated your JSON?
It's not clear how you are trying to access the objects that you say are erroring. The specific line(s) you are having trouble with would be helpful.
It's usually easier to set a pointer to the dictionary you are going to be accessing for readability..
NSDictionary *records = [[objectForKey:#"testlocal_response"] objectForKey#"records"];
then...
NSString *businessName = [records objectForKey:#"business_name"];
float latitude = [[records objectForKey:#"latitude"] floatValue];
Well, I finally sorted it out! I put the records in an NSString, which I could then access using objectAtIndex.
Here is the main Viewcontroller.m code for it:
- (void)viewDidLoad {
[super viewDidLoad];
responseData = [[NSMutableData data] retain];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"*URL TO JSON DATA HERE*"]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
NSMutableArray *touchDirect = [json objectWithString:responseString error:&error];
NSString *touchRecord = [[touchDirect objectForKey:#"touchlocal_response"] objectForKey:#"records"];
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
label.text = [NSString stringWithFormat:#"Connection failed: %#", [error description]];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
NSError *error;
SBJSON *json = [[SBJSON new] autorelease];
//Retrieves the JSON header Data, returning info such as 'status' [which should return 'ok']
NSMutableArray *touchDirect = [json objectWithString:responseString error:&error];
//Puts the records returned into a string called touchRecord
NSString *touchRecord = [[touchDirect objectForKey:#"touchlocal_response"] objectForKey:#"records"];
[responseString release];
// test results
[text appendFormat:#" Address: %#\n", [[touchRecord objectAtIndex:0] objectForKey:#"address1"]];
[text appendFormat:#" Phone: %#\n", [[touchRecord objectAtIndex:0] objectForKey:#"phone"]];
[text appendFormat:#" Address Data record 2: %#\n", [[touchRecord objectAtIndex:1] objectForKey:#"address1"]];
[text appendFormat:#" Phone Data record 2: %#\n", [[touchRecord objectAtIndex:1] objectForKey:#"phone"]];
This now seems to work fine. I also have a if..else if statement to catch errors now. Does this code look Ok?
Thanks for the tip, Nick - I was just trying to get the output right before tidying the code up. I am using an NSMutableArray to put my JSON into initially, is this OK? What is the benefit of putting it into an NSDictionary?
regards,
Robsa