i am very new to something called JSON Parsing in iOS. Can anybody explain me how to parse data from the scratch. Basically what I am tying to tell is that I am using Yahoo weather api for fetching the weather of a location.http://weather.yahooapis.com/forecastjson?w=2502265 is the link that I am using it .Now how can I parse the data from it?
I am getting error by doing this.Can somebody rectify it or tell me how to do it?
NSString * address = #"http://weather.yahooapis.com/forecastjson?w=2502265";
NSString * request = [NSString stringWithFormat:#"%#",address];
NSURL * URL = [NSURL URLWithString:request];
NSString* JSON = [NSString stringWithContentsOfURL:URL encoding:NSUTF8StringEncoding error:&error];
NSError *e = nil;
NSMutableArray *json = [NSJSONSerialization JSONObjectWithData:JSON options:NSJSONReadingMutableContainers error:&e];
NSLog(#"%#", json);
I have found that AFNetworking has made my life much easier.
I usually do something more than this like pass in POST parameters, but this will do for your case:
NSURL *url = [NSURL URLWithString:#"http://weather.yahooapis.com/forecastjson?w=2502265"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
// PARSE YOUR JSON DICTIONARY HERE
[self parseResult:JSON];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Failed to get data from web service, error: %#", [error localizedDescription]);
}];
[operation start];
// method to parse web service JSON
-(void)parseResult:(id)jsonDictionary
{
// parse result here
NSLog(#"Title = %#", [jsonDictionary valueForKey:#"title"];
}
Hope that helps.
Some basic info for you
What you're doing is requesting information from a web service.
You can think of web service like scripts on the server listening for specific POST or GET parameters.
You might have a web service like this:
http://www.mywebservice.com/rest/datatype=User?name=JohnSmith&age=20
Notice the "datatype", "name" and "age" are the parameters the web service is expecting. When you make a request to the web service, you usually pass in the value (in this case, "User", "JohnSmith" and "20" are the values) to those parameters.
These days, a web service will usually return you the data in the form of JSON or XML.
JSON doesn't have to do all those XML formatting, and as a result, JSON will tend to be more of the preferred choice for returning data.
The JSON data returned will look something like:
{
users = {(
({
name = John Smith;
age = 20;
address = 123 Easy Street EARTH
}),
({
name = Bob Brown;
age = 35;
address = 456 Some Road EARTH
})
)};
}
The above can be a bit intimidating at first but once you deal with it once, you'll realise that these are usually dictionaries nested inside arrays, nested inside giant dictionary.
As in the above case, the returned JSON data is a single giant dictionary containing all users. When you do something like:
[JSON objectForKey:#"users"]
You get the "users" array:
users = {(
({
name = John Smith;
age = 20;
address = 123 Easy Street EARTH
}),
({
name = Bob Brown;
age = 35;
address = 456 Some Road EARTH
})
)};
Then when you want to get a specific user from the "users" array, say Bob Brown, you would do something like:
[[JSON objectForKey:#"users"] objectAtIndex:1]
And that will return you:
{
name = Bob Brown;
age = 35;
address = 456 Some Road EARTH
}
Finally, to get a property of a user such as their name, you can go:
[[[JSON objectForKey:#"users"] objectAtIndex:1] valueForKey:#"name"];
For example:
NSLog(#"User name = %#", [[[JSON objectForKey:#"users"] objectAtIndex:1] valueForKey:#"name"]);
Real web service dictionaries usually aren't that nicely formatted, they're usually a bit more convoluted, especially those CMS like Drupal (run!!!) :D
Related
I am using AFNetworking to retrieve information about the weather for a specific location, e.g:
http://api.openweathermap.org/data/2.5/weather?q={New%20York%20City}
I am using the AFNetworking framework but I am having the problems parsing some objects of the JSON.
If I have an NSDictionary with the MAIN object information from the JSON:
NSDictionay *main = [responseObject objectForKey:#"main"];
If I log the main NSDictionary I will get the following valid output:
"main":{
"temp":296.78;
"pressure":1011;
"humidity":69;
"temp_min":293.15;
"temp_max":299.82
};
Although if I create a NSDictionary containing the weather object I will get the following information whenever logging it to the console:
NSDictionay *weather = [responseObject objectForKey:#"weather"];
"weather":(
{
"id":801;
"main":"Clouds";
"description":"few clouds";
"icon":"02d"
}
);
The parsed information contains ( brackets instead of [ from the original response. This does not allow me to correctly access the inside attributes of the weather object.
Summing up, I am able to access all the inside variables of the MAIN object, but I cannot access the attributes of the Weather object (e.g access the icon attribute).
Can someone help me with this ?
Thank you,
You calling your service as below.
NSString *query = #"http://api.openweathermap.org/data/2.5/weather?q={New%20York%20City}";
NSLog(#"%#",query);
query = [query stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSData *jsonData = [[NSString stringWithContentsOfURL:[NSURL URLWithString:query] encoding:NSUTF8StringEncoding error:nil] dataUsingEncoding:NSUTF8StringEncoding];
NSError *error = nil;
NSDictionary *results = jsonData ? [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error] : nil;
Now print Response :
NSLog(#"weather==%#",[results objectForKey:#"weather"]);
NSLog(#"description==%#",[[[results objectForKey:#"weather"] objectAtIndex:0] objectForKey:#"description"]);
NSLog(#"icon==%#",[[[results objectForKey:#"weather"] objectAtIndex:0] objectForKey:#"icon"]);
NSLog(#"id==%#",[[[results objectForKey:#"weather"] objectAtIndex:0] objectForKey:#"id"]);
NSLog(#"main==%#",[[[results objectForKey:#"weather"] objectAtIndex:0] objectForKey:#"main"]);
Your Response is :
whwather==(
{
description = "sky is clear";
icon = 01d;
id= 800;
main= Clear;
}
)
description== "sky is clear";
icon == 01d;
id == 800;
main == Clear;
I am looking for two API calls in Youtube Data API V3.
First I want to get the Channel ID by specifying the name of the channel.
Once I have the Channel ID I want to get n number of videos from that channel.
I am looking for the API calls that I have to make.
Also, does anyone know if there's a chance that channel or video IDs may change at some point? If they can change for the same video/channel then I should not hardcode the ID's in my code.
Thanks
For total newbies who want a running example : consider a function that will help understand the entire cycle of fetch,parse,display etc and bring youtube channel's videos to your tableview specifically. im not writing the tableview part here
-(void)initiateRequestToYoutubeApiAndGetChannelInfo
{
NSString * urlYouCanUseAsSample = #"https://www.googleapis.com/youtube/v3/search?key={YOUR_API_KEY_WITHOUT_CURLY_BRACES}&channelId={CHANNEL_ID_YOU_CAN_GET_FROM_ADDRESS_BAR_WITHOUT_CURLY_BRACES}&part=snippet,id&order=date&maxResults=20";
NSURL *url = [[NSURL alloc] initWithString: urlYouCanUseAsSample];
// Create your request
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// Send the request asynchronously remember to reload tableview on global thread
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
// Callback, parse the data and check for errors
if (data && !connectionError) {
NSError *jsonError;
NSDictionary *jsonResult = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&jsonError];
if (!jsonError) {
// better put a breakpoint here to see what is the result and how it is brought to you. Channel id name etc info should be there
NSLog(#"%#",jsonResult);
/// separating "items" dictionary and making array
//
id keyValuePairDict = jsonResult;
NSMutableArray * itemList = keyValuePairDict[#"items"];
for (int i = 0; i< itemList.count; i++) {
/// separating VIDEO ID dictionary from items dictionary and string video id
id v_id0 = itemList[i];
NSDictionary * vid_id = v_id0[#"id"];
id v_id = vid_id;
NSString * video_ID = v_id[#"videoId"];
//you can fill your local array for video ids at this point
// [video_IDS addObject:video_ID];
/// separating snippet dictionary from itemlist array
id snippet = itemList[i];
NSDictionary * snip = snippet[#"snippet"];
/// separating TITLE and DESCRIPTION from snippet dictionary
id title = snip;
NSString * title_For_Video = title[#"title"];
NSString * desc_For_Video = title[#"description"];
//you can fill your local array for titles & desc at this point
// [video_titles addObject:title_For_Video];
// [video_description addObject:desc_For_Video];
/// separating thumbnail dictionary from snippet dictionary
id tnail = snip;
NSDictionary * thumbnail_ = tnail[#"thumbnails"];
/// separating highresolution url dictionary from thumbnail dictionary
id highRes = thumbnail_;
NSDictionary * high_res = highRes[#"high"];
/// separating HIGH RES THUMBNAIL IMG URL from high res dictionary
id url_for_tnail = high_res;
NSString * thumbnail_url = url_for_tnail[#"url"];
//you can fill your local array for titles & desc at this point
[video_thumbnail_url addObject:thumbnail_url];
}
// reload your tableview on main thread
//[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];
performSelectorOnMainThread:#selector(reloadInputViews) withObject:nil waitUntilDone:NO];
// you can log all local arrays for convenience
// NSLog(#"%#",video_IDS);
// NSLog(#"%#",video_titles);
// NSLog(#"%#",video_description);
// NSLog(#"%#",video_thumbnail_url);
}
else
{
NSLog(#"an error occurred");
}
}
}];
}
First call is a search.list with setting q as channel name and type="channel".
Second one is calling channels.list with that id and get the playlistId of the uploaded videos list.
Third is the playlistItems.list to list videos under that playlist.
Hi here is my code for sending private message to twitter follower/followings,message has been sent but problem is followers are getting message string with %20
-(void)PostOnTwitter :(NSArray *)ParamArray
{
NSLog(#"ParamArray===%#",ParamArray);
if([SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter])
{
if(!accountStore)
accountStore = [[ACAccountStore alloc] init];
ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
[accountStore requestAccessToAccountsWithType:accountType options:nil completion:^(BOOL granted, NSError *error)
{
if(granted!=0)
{
NSArray *twitterAccounts = [self.accountStore accountsWithAccountType:accountType];
NSURL *MsgUrl=[NSURL URLWithString:#"https://api.twitter.com/1.1/direct_messages/new.json"];
NSDictionary *Msgparams = #{#"screen_name" : [ParamArray objectAtIndex:0], #"text" :
[[ParamArray objectAtIndex:1]stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] };
SLRequest *Msgrequest = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodPOST URL:MsgUrl parameters:Msgparams];
[Msgrequest setAccount:[twitterAccounts lastObject]];
[Msgrequest performRequestWithHandler:^(NSData *responseData,NSHTTPURLResponse *urlResponse,NSError *error) {
if (responseData) {
if (urlResponse.statusCode >= 200 && urlResponse.statusCode < 300) {
NSError *jsonError;
NSDictionary *timelineData = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:&jsonError];
if (timelineData) {
[self performSelectorOnMainThread:#selector(CardHasSent) withObject:nil waitUntilDone:NO];
}
}
}
}];
}
}];
}
}
My followers are getting private message like
user%20has%20sent%20you%20a%20card%20from%20happy%20heART%20cards.%20http://www.happyheartcards.net/o.php?t=ODYw
How can I send proper text?Please help.
I think probelm is stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding,but if I don't use NSUTF8StringEncoding message sending fails.
ParamArray has not been encoded earlier ParamArray===(
jry088,
"user has sent you a card from happy heART cards. http://www.happyheartcards.net/o.php?t=OTA1"
)
%20 is indeed the string escape for a space character, and this is the correct behaviour that you are requesting in using stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding. However, the Twitter API does want POST data for direct messages encoded like this:
https://dev.twitter.com/docs/api/1.1/post/direct_messages/new
I thought the most likely thing therefore was that you were running the encoding twice, which would mean that your % in %20s are getting re-encoded to say "Hey, I really mean a percentage sign here.
When I look at the code, there are multiple redundant calls to [ParamArray objectAtIndex:1] and earlier re-encoding of the string data into UTF8:
NSString *StringData = [ParamArray objectAtIndex:1];
const char *cString = [StringData UTF8String];
NSString *Datastringone = [NSString stringWithFormat:#"%s",cString];
NSString *str = [ParamArray objectAtIndex:1];
None of these variables or this processing ever gets used. This made me wonder whether the string in the ParamArray has already been encoded into UTF8 in an earlier part of your application, so that you are encoding it for the second time when you pass it in here.
NSDictionary *Msgparams = #{#"screen_name" : [ParamArray objectAtIndex:0], #"text" :
[[ParamArray objectAtIndex:1]stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] };
EDIT
Actually, I'm going to return to what I originally posted, before I updated the above. I think you're actually getting exactly what you ask for with that encoded text, and the question shouldn't be why you're getting %20s in your text, but rather why the code you've got now is accepting a DM whereas it was failing after all.
If you look at the API reference I linked above (https://dev.twitter.com/docs/api/1.1/post/direct_messages/new) it shows the POST data as % encoded earlier on, but if you actually look at the full code example of what is to be submitted, the string isn't actually encoded at all:
94 "text": "hello, tworld. welcome to 1.1."
So first—change as little else as possible, but remove the encoding stage, and confirm that you still can't send a DM. It could be that you fixed something else without realising it and that is why the POST started working. This would obviously be helped by not embedding the encoding stage into the creation of the dictionary. You get much more readable code if you create all the values separately and then pass the final encoded and prepared variables in when you create the dictionary. A few more temporary variables or pointers may be created but that's well worth it for the increased readability of the code. :)
I need to separate sub person, name, age, home addr, office addr from below given json object retrieved from a website
{ "person" :
[{"subperson":{"home":{"id":"kljljk"},"name":"person3","age":"18","addr":{"home addr":"ksdjr","office addr":"kjshdg"}}}]}
tried nsjsonserialization,sbjson and touchJSON api's. returns a dictionary in which person is the key and everything else is the value(format of json string specified below the code)
my code:
NSURLRequest *urlreq = [NSURLRequest requestWithURL:url];
NSData *response = [NSURLConnection sendSynchronousRequest:urlreq returningResponse:nil error:nil];
[webviv loadRequest:urlreq];
SBJsonParser *jsonparser = [SBJsonParser new];
NSDictionary *json = [jsonparser objectWithData:response];
NSLog(#"%#\n", json);
for(id key in json)
{
NSLog(#"%#=%#",key,[json objectWithKey: key]);
}
//output is
person = (everythingelse starting with [, can't separate name and other required things)
//using NSJSONSerialization
if ([NSJSONSerialization JSONObjectWithData:response options:0 error:&error])
{
NSLog(#"json");
}
NSData *pTL = [NSJSONSerialization JSONObjectWithData:response options:0 error:&error];
NSLog(#"%#",pTL);
//Output is the same
//for(int i=0;i<[pTL count];i++)
//{
//NSLog(#"%d",i);
//}
//even with for loop the output is the same
Tell your backend guys(the person who wrote this web service) to change "[" as "(" and "]" as")". ( is array { is dictionary. [ is nothing for us we can differentiate it
There is a problem with your JSON structure.
For instance, the following is not a legal JSON string:
"subperson":"home":{"id":"kljljk"}
Try replacing it with the following:
{"person":[{"subperson":{"id":"kljljk","name":"person3","age":"18","addr":{"homeaddr":"ksdjr","office addr":"kjshdg"}}}]}
You can use any kind of online JSON parser tool to verify the JSON structure before continuing to debug your code.
Also you should read a little about JSON syntax here.
I am fairly new to iOS development, been at it for 2 years or so. I have developed an app for my Litecoin mining pool that is able to pull data from the API url in JSON format. I am able to get individual variables from JSON, but I want to display all of the data from the "workers" block into a UITableView. Here is an example of the JSON:
{"username":"n00bminer","balance":"0","total_hashrate":"1429","payout_history":"0.71828344","round_shares":"96908","workers":
{
"n00bminer.1":{"hashrate":"998","last_share_timestamp":"1392906308","accepted_shares":"84755","stale_shares":"913"},
"n00bminer.cpu":
{"hashrate":"0","accepted_shares":"7891","stale_shares":"11"},
"n00bminer.2":{"hashrate":"431","last_share_timestamp":"1392906300","accepted_shares":"13285","stale_shares":"118"}
}}
(bolded is the part that I need) Live data: http://www.ielitepool.com/api.php?api_key=9d9be4bd59eb8de59f1cac981099c43e866b0cc07a5555dd922c9efc08ac31a1
I request this using:
NSData* apiData = [NSData dataWithContentsOfURL:
[NSURL URLWithString:[[NSUserDefaults standardUserDefaults] valueForKey:#"api_url"]]
];
NSDictionary* json = nil;
if (apiData) {
json = [NSJSONSerialization
JSONObjectWithData:apiData
options:kNilOptions
error:nil];
}
and get individual variables using:
float total_hashrate = [[json valueForKey:#"total_hashrate"] floatValue];
How can I get all of the workers, as well as their stats in one UITableView. For example, I don't want the worker name to only display, then have it lead to another UITableViewController, but rather the name and then the stats underneath (hashrate, accepted_shares, etc.)
Following code will print worker's information:
[json[#"workers"] enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSDictionary *obj, BOOL *stop) {
NSLog(#"worker = %# : hashrate = %f last_share_timestamp = %f",
key, [obj[#"hashrate"] floatValue], [obj[#"last_share_timestamp"] floatValue] );
}];
If you will have troubles displaying info in table, please create separate question with code sample.