Can I write JSON data to a file in iOS/Objective-C? - objective-c

I need to write JSON data to a file using Objective-C. My data looks something like this:
data = {
"NrObjects" : "7",
"NrScenes" : "5",
"Scenes" : [
{ "dataType" : "label", "position" : [20, 20, 300, 300], "value" : "Hello" },
{ "dataType" : "label", "position" : [20, 60, 300, 300], "value" : "Hi There" }
]
}
It may get more complex than this, but what I need to know is whether I can do this with Obj-C, i.e., create an object of this form, write the data to a file, and read it back.

There is a class specifically made for this, its called NSJSONSerialization.
You read it like this:
NSArray* jsonResponse = [NSJSONSerialization JSONObjectWithData:theResponse
options:kNilOptions
error:&error];
and write it like this:
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:userDetails
options:kNilOptions
error:&error];

write:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:jsonObject];
[data writeToFile:path atomically:YES];
read:
NSData *data = [NSData dataWithContentsOfFile:path];
NSDictionary *jsonObject = [NSKeyedUnarchiver unarchiveObjectWithData:data];

Related

Retrieve nested objects from JSON - Objective C

I seem to be having a small issue with the parsing through a nested JSON result. The following code works perfectly if the JSON is not nested. I'm a littler perplexed on how to proceed as every attempted (through examples of others) have failed.
So, to test this I'm using the following API from https://developer.worldweatheronline.com/page/explorer-free
I simply would like to get my current temperature (temp_c).
Below is the code calling the service. Note that I have an NSObject that will fill the data, but of course I can't seem to get to that stage. Also it is an NSMutableArray throughout. Again, I don't think that is the issue but provides context.
-(void)retrieveLocalWeatherService {
NSURL *url = [NSURL URLWithString:getLocalWeather];
NSData *data = [NSData dataWithContentsOfURL:url];
jsonArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
//set up array and json call
weatherArray = [[NSMutableArray alloc]init];
//Loop through the JSON array
for (int i = 0; i< jsonArray.count; i++)
{
//create our object
NSString *nTemp = [[jsonArray objectAtIndex:i]objectForKey:#"temp_C"];
NSString *nPressure = [[jsonArray objectAtIndex:i]objectForKey:#"pressure"];
NSString *nHumidity = [[jsonArray objectAtIndex:i]objectForKey:#"humidity"];
//Add the object to our animal array
[weatherArray addObject:[[LocalWeather alloc]initWithtemp:(nTemp) andpressure:nPressure andhumidity:nHumidity]];
}
Here is the JSON response.
{
"data": {
"current_condition": [
{
"cloudcover": "75",
"FeelsLikeC": "31",
"FeelsLikeF": "88",
"humidity": "70",
"observation_time": "05:15 AM",
"precipMM": "0.0",
"pressure": "1011",
"temp_C": "28",
"temp_F": "82",
"visibility": "10",
"weatherCode": "116",
"weatherDesc": [
{
"value": "Partly Cloudy"
}
],
"weatherIconUrl": [
{
"value": "http://cdn.worldweatheronline.net/images/wsymbols01_png_64/wsymbol_0002_sunny_intervals.png"
}
],
"winddir16Point": "N",
"winddirDegree": "10",
"windspeedKmph": "41",
"windspeedMiles": "26"
}
],
"request": [
{
"query": "Brisbane, Australia",
"type": "City"
}
],
I cut off the JSON service as it goes for miles, so where am I going wrong? I believe its somewhere within "for-loop" but am unsure where. I know its major node is "data" and then sub-node is "current_condition". Should I be digging through the JSON results? If what is the best approach.
BTW, I'm getting a response from the server with the entire JSON result..clearly a parsing issue on my part.
Thanks in advance!
please be kind i'm a newbie.
You are parsing your JSON data in wrong way, you are parsing JSON directly to Array but as per your JSON format your JSON will return an NSDictionary not NSArray.
-(void)retrieveLocalWeatherService {
NSURL *url = [NSURL URLWithString:getLocalWeather];
NSData *data = [NSData dataWithContentsOfURL:url];
NSDictionary *weatherJson = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
NSArray *currentConditionArray = [weatherJson valueForKeyPath:#"Data.current_condition"];
//set up array and json call
weatherArray = [[NSMutableArray alloc]init];
//Loop through the JSON array
for (NSDictionary *item in currentConditionArray)
{
//create our object
NSString *nTemp = [item objectForKey:#"temp_C"];
NSString *nPressure = [item objectForKey:#"pressure"];
NSString *nHumidity = [item objectForKey:#"humidity"];
//Add the object to our animal array
[weatherArray addObject:[[LocalWeather alloc]initWithtemp:(nTemp) andpressure:nPressure andhumidity:nHumidity]];
}
}

Using JSON in iOS before server is online - include in file as string

I'm working on an application in iOS that gets some of its information from a server using JSON. The server's not online yet, so I'm trying to use what the developers working on the server have given me as sample code to build from. I thought the easiest way to do this would be storing the JSON response in a string and using NSJSONSerialization.
The code I'm trying looks as follows:
NSString * JSONString = #"{\"firstName\":\"John\", \"lastName\": \"Smith\", \"age\": 25, \"address\": {\"streetAddress\": \"21 2nd Street\",\"city\": \"New York\", \"state\": \"NY\",\"postalCode\": \"10021\"},}";
bool valid = [NSJSONSerialization isValidJSONObject:JSONString];
if (valid) {
NSLog(#"Valid JSON");
} else {
NSLog(#"Invalid JSON");
}
Which always logs, "Invalid JSON."
All of my research has given resources about how to get the data from a server, but nothing about testing before the server is available. Any ideas?
Two issues. First, your JSON string has an extra comma. It should be:
NSString *jsonString = #"{\"firstName\":\"John\", \"lastName\": \"Smith\", \"age\": 25, \"address\": {\"streetAddress\": \"21 2nd Street\",\"city\": \"New York\", \"state\": \"NY\",\"postalCode\": \"10021\"}}";
Second, though, your original code has a false negative. A string will always fail isValidJSONObject. That method is not for validating a JSON string. If you want to use isValidJSONObject, you should pass it a NSDictionary, e.g.:
NSDictionary* jsonDictionary = #{
#"firstName" : #"John",
#"lastName" : #"Smith",
#"age" : #(25),
#"address" : #{
#"streetAddress": #"21 2nd Street",
#"city" : #"New York",
#"state" : #"NY",
#"postalCode" : #"10021"
}
};
BOOL valid = [NSJSONSerialization isValidJSONObject:jsonDictionary];
if (valid) {
NSLog(#"Valid JSON");
} else {
NSLog(#"Invalid JSON");
}
So, the best way to create a JSON string is to create the dictionary like above, and then invoke dataWithJSONObject. I generally would advise against writing a JSON string manually, because you can always introduce typos like your extra comma. I always build a JSON string from a NSDictionary like this, because you never have to worry about whether the string is well formed or not. NSJSONSerialization takes care of the hard work of formatting the string properly:
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonDictionary
options:0
error:&error];
if (error)
NSLog(#"dataWithJSONObject error: %#", error);
NSString *jsonString = [[NSString alloc] initWithData:jsonData
encoding:NSUTF8StringEncoding]);
NSLog(#"JSON string is: %#", jsonString);
That yields:
{"age":25,"lastName":"Smith","firstName":"John","address":{"streetAddress":"21 2nd Street","state":"NY","city":"New York","postalCode":"10021"}}
Or, if you use the NSJSONWritingPrettyPrinted option to dataWithJSONObject:
{
"age" : 25,
"lastName" : "Smith",
"firstName" : "John",
"address" : {
"streetAddress" : "21 2nd Street",
"state" : "NY",
"city" : "New York",
"postalCode" : "10021"
}
}
I test by keeping a file in my resources say, test.json. You can open it with the following code:
NSString *path = [NSBundle.mainBundle pathForResource:#"test.json" ofType:#"json"];
NSError *error = nil;
NSString *fileContents = [NSString stringWithContentsOfFile:path
encoding:NSUTF8StringEncoding
error:&error];
Then call the method to convert to a JSON object. The test file will be more readable than what you have above. Hope this helps!

Best approaches on "filling" a json file , iOS?

I am working on an application and i need to send some data to my server. The data is in json format and more specific the json file looks like this :
{
"eventData": {
"eventDate": "Jun 13, 2012 12:00:00 AM",
"eventLocation": {
"latitude": 43.93838383,
"longitude": -3.46
},
"text": "hjhj",
"imageData": "raw data",
"imageFormat": "JPEG",
"expirationTime": 1339538400000
},
"type": "ELDIARIOMONTANES",
"title": "accIDENTE"
}
So i have tried to hardcode the data in my json file and everything works ok. Now what i am trying to do is to fill my json file , using variables so everything can work automatcally when data changes. What would a good approach be for that?? Some sample code would be highly appreciated as i am very new to obj-c. Thanks for ur time! :D
EDIT
Ok so an NSDictionary seems a nice way to go.
But how can i create a dictionary to look like the json format?? I ve only used dictionaries like this :
NSArray *keys = [NSArray arrayWithObjects:#"eventDate", #"eventLocation", #"latitude" nil];
NSArray *objects = [NSArray arrayWithObjects:#"object1", #"object2", #"object3", nil];
dictionary = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
For the langitude and longitude for example it is a pair of key and value but for the rest??
All you need is a NSDictionary containing your keys and values. Since iOS5, you can proceed with the following code
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:myDictionary
options:NSJSONWritingPrettyPrinted
error:&error];
if (!jsonData) {
NSLog(#"Got an error: %#", error);
} else {
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
// ...
}
I have used this library . It is very simple and useful. And for tutorial check this site.

How to get the object types with JSONKit

I'm trying to decoder a json file and get value type for each unknowing the atributes names or the order.
Ie.
{
"Name": "Klove",
"Altitude": "100",
"Latitude": "43.421985",
"Longitude": "-5.823897"
}
So: Name will be a NString with Klove inside. Latitude a float with 43.421985....
//File initialization
NSString *filePath = [[NSBundle mainBundle]
pathForResource:#"buildings" ofType:#"json"];
NSData *fileContent = [NSData dataWithContentsOfFile:filePath];
JSONDecoder *jsonKitDecoder = [JSONDecoder decoder];
NSDictionary *dict = [jsonKitDecoder objectWithData:fileContent];
// the party starts
for (NSDictionary *poi in dict) {
for (int i = 0; i <= [[poi allKeys]count]-1 ; i++) {
// Here i'm trying to get the object type (but never with success)
if([[poi objectForKey:[[poi allKeys]objectAtIndex:i]]
isKindOfClass:[NSNumber class]]
|| [[poi objectForKey:[[poi allKeys]objectAtIndex:i]]
isKindOfClass:[NSArray class]]
|| [[poi objectForKey:[[poi allKeys]objectAtIndex:i]]
isKindOfClass:[NSDictionary class]])
{
NSLog(#"Other kind of class detected");
// do somthing but never happens
// in fact, if i use [[poi objectForKey:[[poi allKeys]objectAtIndex:i]class]
// always is __NSCFString
}
NSLog(#"%#",[[poi allKeys]objectAtIndex:i]);
NSLog(#"%#",[poi objectForKey:[[poi allKeys]objectAtIndex:i]]);
}
}
So... I don't know how could i get the type of the object in the json dictionary. Any idea? If is possible I wouldn't like to make checks like:
if ([poi allKeys]objectAtIndex:i] isEqualToString(#"Latitude"))
[[poi objectForKey:i]floatValue];
Thanks in advance.
Ok. My fault.
If I define the JSON file like:
{
"Name": "Klove",
"Altitude": 100,
"Latitude": 43.421985,
"Longitude": -5.823897
}
instead the above format I'll get the types automatically with the JSONKit.
To get the type in my code:
[poi objectForKey:[[poi allKeys]objectAtIndex:i]]

How do I parse JSON with Objective-C?

I am new to iPhone. Can anyone tell me the steps to follow to parse this data and get the activity details, first name, and last name?
{
"#error": false,
"#data": {
"": {
"activity_id": "35336",
"user_id": "1",
"user_first_name": "Chandra Bhusan",
"user_last_name": "Pandey",
"time": "1300870420",
"activity_details": "Good\n",
"activity_type": "status_update",
"photo_url": "http://184.73.155.44/hcl-meme/QA_TEST/sites/default/files/pictures/picture-1627435117.jpg"
},
"boolean": "1",
"1": {
"1": {
"photo_1_id": "9755"
},
"activity_id": "35294",
"album_name": "Kalai_new_Gallery",
"user_id": "31",
"album_id": "9754",
"user_first_name": "Kalaiyarasan",
"user_last_name": "Balu",
"0": {
"photo_0_id": "9756"
},
"time": "1300365758",
"activity_type": "photo_upload",
"photo_url": "http://184.73.155.44/hcl-meme/QA_TEST/"
},
"3": {
"activity_id": "35289",
"user_id": "33",
"user_first_name": "Girija",
"user_last_name": "S",
"time": "1300279636",
"activity_details": "girija Again\n",
"activity_type": "status_update",
"photo_url": "http://184.73.155.44/hcl-meme/QA_TEST/sites/default/files/pictures/picture-33-6361851323080768.jpg"
},
"2": {
"owner_first_name": "Girija",
"activity_id": "35290",
"activity_details": "a:2:{s:4:\"html\";s:51:\"!user_fullname and !friend_fullname are now friends\";s:4:\"type\";s:10:\"friend_add\";}",
"activity_type": "friend accept",
"owner_last_name": "S",
"time": "1300280400",
"photo_url": "http://184.73.155.44/hcl-meme/QA_TEST/sites/default/files/pictures/picture-33-6361851323080768.jpg",
"owner_id": "33"
},
"4": {
"activity_id": "35288",
"user_id": "33",
"user_first_name": "Girija",
"user_last_name": "S",
"time": "1300279530",
"activity_details": "girija from mobile\n",
"activity_type": "status_update",
"photo_url": "http://184.73.155.44/hcl-meme/QA_TEST/sites/default/files/pictures/picture-33-6361851323080768.jpg"
}
}
}
With the perspective of the OS X v10.7 and iOS 5 launches, probably the first thing to recommend now is NSJSONSerialization, Apple's supplied JSON parser. Use third-party options only as a fallback if you find that class unavailable at runtime.
So, for example:
NSData *returnedData = ...JSON data, probably from a web request...
// probably check here that returnedData isn't nil; attempting
// NSJSONSerialization with nil data raises an exception, and who
// knows how your third-party library intends to react?
if(NSClassFromString(#"NSJSONSerialization"))
{
NSError *error = nil;
id object = [NSJSONSerialization
JSONObjectWithData:returnedData
options:0
error:&error];
if(error) { /* JSON was malformed, act appropriately here */ }
// the originating poster wants to deal with dictionaries;
// assuming you do too then something like this is the first
// validation step:
if([object isKindOfClass:[NSDictionary class]])
{
NSDictionary *results = object;
/* proceed with results as you like; the assignment to
an explicit NSDictionary * is artificial step to get
compile-time checking from here on down (and better autocompletion
when editing). You could have just made object an NSDictionary *
in the first place but stylistically you might prefer to keep
the question of type open until it's confirmed */
}
else
{
/* there's no guarantee that the outermost object in a JSON
packet will be a dictionary; if we get here then it wasn't,
so 'object' shouldn't be treated as an NSDictionary; probably
you need to report a suitable error condition */
}
}
else
{
// the user is using iOS 4; we'll need to use a third-party solution.
// If you don't intend to support iOS 4 then get rid of this entire
// conditional and just jump straight to
// NSError *error = nil;
// [NSJSONSerialization JSONObjectWithData:...
}
Don't reinvent the wheel. Use json-framework or something similar.
If you do decide to use json-framework, here's how you would parse a JSON string into an NSDictionary:
SBJsonParser* parser = [[[SBJsonParser alloc] init] autorelease];
// assuming jsonString is your JSON string...
NSDictionary* myDict = [parser objectWithString:jsonString];
// now you can grab data out of the dictionary using objectForKey or another dictionary method
NSString* path = [[NSBundle mainBundle] pathForResource:#"index" ofType:#"json"];
//将文件内容读取到字符串中,注意编码NSUTF8StringEncoding 防止乱码,
NSString* jsonString = [[NSString alloc] initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
//将字符串写到缓冲区。
NSData* jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *jsonError;
id allKeys = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONWritingPrettyPrinted error:&jsonError];
for (int i=0; i<[allKeys count]; i++) {
NSDictionary *arrayResult = [allKeys objectAtIndex:i];
NSLog(#"name=%#",[arrayResult objectForKey:#"storyboardName"]);
}
file:
[
{
"ID":1,
"idSort" : 0,
"deleted":0,
"storyboardName" : "MLMember",
"dispalyTitle" : "76.360779",
"rightLevel" : "10.010490",
"showTabBar" : 1,
"openWeb" : 0,
"webUrl":""
},
{
"ID":1,
"idSort" : 0,
"deleted":0,
"storyboardName" : "0.00",
"dispalyTitle" : "76.360779",
"rightLevel" : "10.010490",
"showTabBar" : 1,
"openWeb" : 0,
"webUrl":""
}
]
JSON parsing using NSJSONSerialization
NSString* path = [[NSBundle mainBundle] pathForResource:#"data" ofType:#"json"];
//Here you can take JSON string from your URL ,I am using json file
NSString* jsonString = [[NSString alloc] initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
NSData* jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *jsonError;
NSArray *jsonDataArray = [NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&jsonError];
NSLog(#"jsonDataArray: %#",jsonDataArray);
NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&jsonError];
if(jsonObject !=nil){
// NSString *errorCode=[NSMutableString stringWithFormat:#"%#",[jsonObject objectForKey:#"response"]];
if(![[jsonObject objectForKey:#"#data"] isEqual:#""]){
NSMutableArray *array=[jsonObject objectForKey:#"#data"];
// NSLog(#"array: %#",array);
NSLog(#"array: %d",array.count);
int k = 0;
for(int z = 0; z<array.count;z++){
NSString *strfd = [NSString stringWithFormat:#"%d",k];
NSDictionary *dicr = jsonObject[#"#data"][strfd];
k=k+1;
// NSLog(#"dicr: %#",dicr);
NSLog(#"Firstname - Lastname : %# - %#",
[NSMutableString stringWithFormat:#"%#",[dicr objectForKey:#"user_first_name"]],
[NSMutableString stringWithFormat:#"%#",[dicr objectForKey:#"user_last_name"]]);
}
}
}
You can see the Console output as below :
Firstname - Lastname : Chandra Bhusan - Pandey
Firstname - Lastname : Kalaiyarasan - Balu
Firstname - Lastname : (null) - (null)
Firstname - Lastname : Girija - S
Firstname - Lastname : Girija - S
Firstname - Lastname : (null) - (null)
I recommend and use TouchJSON for parsing JSON.
To answer your comment to Alex. Here's quick code that should allow you to get the fields like activity_details, last_name, etc. from the json dictionary that is returned:
NSDictionary *userinfo=[jsondic valueforKey:#"#data"];
NSDictionary *user;
NSInteger i = 0;
NSString *skey;
if(userinfo != nil){
for( i = 0; i < [userinfo count]; i++ ) {
if(i)
skey = [NSString stringWithFormat:#"%d",i];
else
skey = #"";
user = [userinfo objectForKey:skey];
NSLog(#"activity_details:%#",[user objectForKey:#"activity_details"]);
NSLog(#"last_name:%#",[user objectForKey:#"last_name"]);
NSLog(#"first_name:%#",[user objectForKey:#"first_name"]);
NSLog(#"photo_url:%#",[user objectForKey:#"photo_url"]);
}
}