NSDictionary throws exception not logical for me - ios

Good day.Im requesting to some server and defiantly I'm having some JSON data there so I'm trying to parse it.Im stuck at the point where I'm actually parsing it.So i have method called parseJson which requires NSDictionry as parameter so here how it looks
-(void)parseJson:(NSDictionary*)jsonData{
[jsonData valueForKey:#"email"];
}
as you can see not much here but I'm getting exeption when the code reaches at
[jsonData valueForKey:#"email"];
I have pretty much started developing for iOS from yesterday and the exception is hell as weird for me which is the next.
this class is not key value coding-compliant for the key email.'
So by googling i found nothing...and pretty much in every JSON PARSING tutorial this one line code is written so I'm very much confused what does this exception means....Please help,what am i doing wrong?
FULL REQUEST CODE
-(void) makeRequest{
// Create the request.
__block NSString *returnResponse = #"hello";
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue ]];
//Create an URLRequest
NSURL *url = [NSURL URLWithString:#"http://jsonplaceholder.typicode.com/posts"];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
//Create POST Params and add it to HTTPBody
NSString *params = #"api_key=APIKEY&email=example#example.com&password=password";
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];
//Create task
NSURLSessionDataTask * dataTask =[defaultSession dataTaskWithRequest: urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if(response!=NULL){
returnResponse =[NSString stringWithFormat:#"%#",response];
}else{
returnResponse = [NSString stringWithFormat:#"%#",error.description];
}
[self hideSpinner];
NSString* jsonString = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
[self parseJson:jsonString];
}];
[dataTask resume];
}
Ok i have changed the method now to
-(void)parseJson:(NSString*)jsonData{
NSDictionary * dictionary = [[NSDictionary alloc] initWithContentsOfFile:jsonData];
NSLog(#"%#",jsonData);
NSString* mystring = [dictionary valueForKey:#"email"];
NSLog(#"%#",mystring);
}
and here is the output i get when logging the strings
2016-01-22 00:25:48.690 testproject[627:83537] {
"api_key": "APIKEY",
"email": "example#example.com",
"password": "password",
"id": 101
}
2016-01-22 00:25:48.690 testproject[627:83537] (null)
As you can see the exception problem gone,but now i get NULL value..but you can see that just a one line above i got my son with email key string....so i have fully no clue whats going on.

valueForObject:method has nothing to do with NSDictionary. It is used by KVO which stands for Key-Value Observing. You can retrieve object from NSDictionary by using [] or objectForKey: method. Here are the examples:
dictionary[#"email"]
//or
[dictionary objectForKey:#"email"]
//EDITED
Instead of converting NSObject to NSString and trying accessing properties with KVO or dictionary methods/syntax please try to parse NSData using the code below:
NSDictionary *JSONDictionary =[NSJSONSerialization JSONObjectWithData:data options:0 error:nil]
NSString *email = JSONDictionary[#"email"];
You should be able to retrieve objects from the JSONDictionary using methods/syntax mentioned by me in the first version of the answer.

Related

Send email in Gmail API - Objective C

We are working on an iOS project that involves sending emails through the Gmail API and we are having trouble finding documentation on how to actually do this.
First, we haven't completely figured out authentication. We are using AppAuth to handle that, and it's worked pretty well so far, but we are not quite sure how to link that up to the Gmail API in our code.
Second, how do we send the message itself? We have the content and everything formatted, we just can't figure out how to actually send the message. All we are looking to do is send a simple message to a specified email address from the user's own email account; no attachments or anything like that. We have seen a couple swift examples, however we would prefer to use Objective C. Any ideas on how we could do this?
Update:
After playing around with things a bit more, we found another way to connect to Gmail. Instead of using the classes from the Google API Objective C Client for REST, we are simply trying to send the email using an HTTP POST method. This appears to be way easier than dealing with all of the errors we were getting before. The only problem we have now is that we still can't quite send messages. With nearly everything we've tried, the API just creates an empty message and puts it in our Sent mailbox; that's it. Here's what we have right now:
- (void)sendEmail{
NSURL *userinfoEndpoint = [NSURL URLWithString:#"https://www.googleapis.com/upload/gmail/v1/users/TEST_USERNAME/messages/send?uploadType=media"];
NSString *currentAccessToken = _authState.lastTokenResponse.accessToken;
[self logMessage:#"Trying to authenticate...."];
// Handle refreshing tokens
NSString *message = [NSString stringWithFormat:#"{\"raw\": \"%#\"}",[self generateMessage]];
NSLog(#"%#", message);
// creates request to the userinfo endpoint, with access token in the Authorization header
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:userinfoEndpoint];
NSString *authorizationHeaderValue = [NSString stringWithFormat:#"Bearer %#", accessToken];
[request addValue:authorizationHeaderValue forHTTPHeaderField:#"Authorization"];
[request setHTTPMethod:#"POST"];
[request setValue:#"message/rfc822" forHTTPHeaderField:#"Content-Type"];
[request setValue:[NSString stringWithFormat:#"%lu", (unsigned long)[message length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:[message dataUsingEncoding:NSUTF8StringEncoding];
NSURLSessionConfiguration *configuration =
[NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
delegate:nil
delegateQueue:nil];
// performs HTTP request
NSURLSessionDataTask *postDataTask =
[session dataTaskWithRequest:request
completionHandler:^(NSData *_Nullable data,
NSURLResponse *_Nullable response,
NSError *_Nullable error) {
// Handle response
}];
[postDataTask resume];
}];
}
- (NSString *)generateMessage{
NSString *message = [NSString stringWithFormat:#"From: <TEST_USER#domain.com>\nTo: <TEST_USER#domain.com>\nSubject: Test\n\nThis is a test"];
NSString *rawMessage = [message stringByReplacingOccurrencesOfString:#"\\n" withString:#"\n"];
NSData *encodedMessage = [rawMessage dataUsingEncoding:NSUTF8StringEncoding];
NSString *encoded = [encodedMessage base64EncodedStringWithOptions:0];
NSLog(#"%#", encoded);
return encoded;
}
We have tested the encoding part and it is making a proper base64 string, however after that point, something clearly is not formatted right or something. We get a confirmation that the message was successfully created, however all the API does is create an empty email with no recipient, subject, or body. Any ideas on what we could do to get this to work?
I'm not an expert in this but I remembered we have done something similar in the past. Follow the instructions at the following link and make sure that you select the proper option in Gmail API wizard
https://developers.google.com/gmail/api/quickstart/ios?ver=objc
I hope you find this helpful
After numerous experimentations, here is the code that seems to finally work for me, i worked it off your example above.
1st you need to create google project in dev console, get its Client ID and Api-Key(this may not be necessary) and implement Google SignIn in AppDelegete in - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions method:
[GIDSignIn sharedInstance].clientID = #"your proj client id here";
[GIDSignIn sharedInstance].delegate = self;
[GIDSignIn sharedInstance].scopes=[NSArray arrayWithObjects:#"https://www.googleapis.com/auth/gmail.send",#"https://www.googleapis.com/auth/gmail.readonly",#"https://www.googleapis.com/auth/gmail.modify", nil];
Now sending emails:
// refresh token
appDelegate.delAuthAccessToken=#"";
[[GIDSignIn sharedInstance] signInSilently];
NSDate *timeStart = [NSDate date];
NSTimeInterval timeSinceStart=0;
while([appDelegate.delAuthAccessToken isEqualToString:#""] && timeSinceStart<10){//wait for new token but no longer than 10s should be enough
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate dateWithTimeIntervalSinceNow:1.0f]];//1sec increment actually ~0.02s
timeSinceStart = [[NSDate date] timeIntervalSinceDate:timeStart];
}
if (timeSinceStart>=10) {//timed out
return;
}
//compose rfc2822 message AND DO NOT base64 ENCODE IT and DO NOT ADD {raw etc} TOO, put 'To:' 1st, add \r\n between the lines and double that before the actual text message
NSString *message = [NSString stringWithFormat:#"To: %#\r\nFrom: %#\r\nSubject: EzPic2Txt\r\n\r\n%#", appDelegate.delToEmails, appDelegate.delAuthUserEmail, appDelegate.delMessage];
NSURL *userinfoEndpoint = [NSURL URLWithString:#"https://www.googleapis.com/upload/gmail/v1/users/me/messages/send?uploadType=media"];
NSLog(#"%#", message);
//create request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:userinfoEndpoint];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[message dataUsingEncoding:NSUTF8StringEncoding]];//message is plain UTF8 string
//add all headers into session config, maybe ok adding to request too
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
configuration.HTTPAdditionalHeaders = #{
#"api-key" : #"api-key here, may not need it though",
#"Authorization" : [NSString stringWithFormat:#"Bearer %#", appDelegate.delAuthAccessToken],
#"Content-type" : #"message/rfc822",
#"Accept" : #"application/json",
#"Content-Length": [NSString stringWithFormat:#"%lu", (unsigned long)[message length]]
};
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
// performs HTTP request
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
// Handle response
}];
[postDataTask resume];
Hope it helps somebody
In my app I used to be able to use MailCore2 but it got blocked by Google (I got access denied when I switched to permitted send, readonly and modify scopes) since MailCore2 works only with FULL permissions. Google allowed to use ONLY send, readonly and modify scopes. There is no guide lines how to use their "great restful api" with Gmail in iOS though, so it seems like HTTP POST is the last resort until they shut it down too.
I cannot have my app to be deemed by Google as insecure. If you are OK with that you can still use MailCore2, no problem.
Receiving email with HTTP GET:
1st get up to 20 unread messages ids:
//get IDs of no more than 20 unread messages
//in query you can add extra filters, say messages only from specific emails
NSString *query=#"from:aaa#gmail.com|from:bbb#yahoo.com";
NSString *tmpStr=[NSString stringWithFormat:#"https://www.googleapis.com/gmail/v1/users/me/messages?maxResults=20&q=\"is:unread\" \"%#\"",query];
NSString *tmpStrURL=[tmpStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *userinfoEndpoint = [NSURL URLWithString:tmpStrURL];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:userinfoEndpoint];
[request setHTTPMethod:#"GET"];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
configuration.HTTPAdditionalHeaders = #{#"api-key" : #"your api key here",
#"Authorization" : [NSString stringWithFormat:#"Bearer %#", yourTokenHere],
#"Accept" : #"application/json"
};
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
// performs HTTP request
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
// Handle response
if (!error){
NSMutableDictionary *jsondata = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
long jsonMsgsCnt = [[jsondata valueForKey:#"resultSizeEstimate"] longValue];
if(jsonMsgsCnt>0){
NSMutableArray *jsonMsgs = [jsondata objectForKey:#"messages"];
for (NSMutableDictionary *tmp in jsonMsgs){
[delMsgsReceived addObject:[tmp objectForKey:#"id"]];
}
}
NSLog(#"retrieve Email Id postDataTask n msg:%li",delMsgsReceived.count);
}else{
NSLog(#"retrieve Email Id postDataTask error:%#",error.description);
}
}];
[postDataTask resume];
Now delMsgsReceived contains messagesIds. Process them to get actual emails one by one:
NSString *tmpStr=[NSString stringWithFormat:#"https://www.googleapis.com/gmail/v1/users/me/messages/%#?format=full", msgId];//supply message id here
NSString *tmpStrURL=[tmpStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *userinfoEndpoint = [NSURL URLWithString:tmpStrURL];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:userinfoEndpoint];
[request setHTTPMethod:#"GET"];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
configuration.HTTPAdditionalHeaders = #{
#"api-key" : #"your api key",
#"Authorization" : [NSString stringWithFormat:#"Bearer %#", your auth token],
#"Accept" : #"application/json"
};
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
// performs HTTP request
NSURLSessionDataTask *postDataTask =
[session dataTaskWithRequest:request
completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
// Handle response
if (!error){
NSMutableDictionary *jsondata = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
NSString *body=[jsondata objectForKey:#"snippet"];//not full msg!
//for full message get the whole payload and extract what you need from there NSMutableArray *jsonPayload = [[jsondata objectForKey:#"payload"] objectForKey:#"headers"];
}else{
//deal with error
NSLog(#"retrieving message error:%#",error.description);
}
}];
[postDataTask resume];

How to save the response From My server , and How can i access That data

Hi i am getting the response from my server successfully.i need to access the user_id send by the server in my app.
check my code:
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
NSURL * url = [NSURL URLWithString:#"my url"];
NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:url];
NSString * params=[[NSString alloc]initWithFormat:#"mobile=%#",[self.reqnum text ]];
NSLog(#"%#",params);
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];
NSURLSessionDataTask * dataTask =[defaultSession dataTaskWithRequest:urlRequest
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(#"Response:%# %#\n", response, error);
if(error == nil)
{
NSString * text = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog(#"Data = %#",text);
[[NSUserDefaults standardUserDefaults]setObject:#"Y" forKey:#"login"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}];
[dataTask resume];
for this code i am getting the response like:
here i need to access the user_id in my app .so can i get that particular user_id.
Thank You.
Since original solutions have already been posted, I will focus on longer & more tedious way which I think is the proper way to handle the elephant in the room. This will help you in the longer run.
Create a Singleton class since there can be only one user logged in at one time.
SharedUser.h
#import <Foundation/Foundation.h>
#interface SharedUser : NSObject
#property (strong, nonatomic) NSString* userId;
#property (strong, nonatomic) NSString* userName;
#property (strong, nonatomic) NSString* subscriptionStatus;
#property (strong, nonatomic) NSString* registerDate;
#property (strong, nonatomic) NSString* expiryDate;
+(SharedUser*) getInstance;
#end
SharedUser.m
#import "SharedUser.h"
#implementation SharedUser
static SharedUser * sharedInstance;
+(SharedUser*) getInstance
{
#synchronized(self)
{
if(sharedInstance == nil)
{
sharedInstance = [[SharedUser alloc] init];
sharedInstance.userName = #"";
sharedInstance.userId = #"";
sharedInstance.subscriptionStatus = #"";
sharedInstance.registerDate = #"";
sharedInstance.expiryDate = #"";
return sharedInstance;
}
else
{
return sharedInstance;
}
}
}
Convert your response into NSDictionary.
NSDictionary *json_dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];;//From Santosh Reddy's Answer
Populate your sharedInstance with the result attributes:
[SharedUser getInstance].userId = [json_dict objectForKey:#"user_id"];
[SharedUser getInstance].userName = [json_dict objectForKey:#"username"];
[SharedUser getInstance].subscriptionStatus = [json_dict objectForKey:#"subscription_status"];
[SharedUser getInstance].registryDate = [json_dict objectForKey:#"register_date"];//Better to use NSDate type instead of NSString
[SharedUser getInstance].expiryDate = [json_dict objectForKey:#"expiry_date"];
Now your user's attributes will be available anywhere in the App. You just need to import SharedUser.h to desired UIView, UIViewController & type following to access your data:
NSString *userId = [SharedUser getInstance].userId;
Also Note that I am using singleton pattern because I am assuming that you only need to handle one user's attributes which will be used in multiple viewcontrollers over the span of time. If you need multiple users saved, create a similar user model class and populate them in a similar way. (Just don't make them singleton).
Also I would suggest that you should read Ray Wenderlich's series tutorials on:
1. Object Oriented Design
2. Design Patterns
3. Intro to iOS design patterns
If you want to use the value in other classes then :
First create a data Model Class, parse the data dictionary/JSON and store it.
Using the completion block you can return the specific/received user_id to the caller.
Here you are getting in JSON, you can parse it and get the desired data:
NSDictionary *respDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
NSString *userID = respDict[#"user_id"];
The response is a JSON object. If what you are asking is how to parse it, then there is an inbuilt JSON parser in iOS.
NSDictionary *json_dict = [text JSONValue];
NSString *userID = [result objectForKey:#"user_id"];
Create a NSDictionary to get json data.
NSURLSessionDataTask * dataTask =[defaultSession dataTaskWithRequest:urlRequest
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(#"Response:%# %#\n", response, error);
if(error == nil)
{
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
NSString *userID = [dictionary objectForKey:#"user_id"];
}
}];
Yes, its upto you how to store data and if you want to parse it, then try
NSDictionary *jsonDict = [responseString JSONValue];
NSString *user_id = [jsonDict objectForKey:#"user_id"];
Parse the data that you're getting in block as below.
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(#"Response:%# %#\n", response, error);
if(error == nil)
{
NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
NSDictionary *response = JSON[#"user_id"];
}
}];
You can make a NSDictionary, save JSON data in it and fetch user_id from it. Like this:
NSDictionary *dictionaryName=[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
NSString *user_id= [dictionaryName valueForKey:#"user_id"];

IOS Float Not Being Sent Through POST Request

I am have been trying to send a post request from one of my ViewControllers which collects some data from another ViewController through
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
Anyways when I try to send the post request to send variables to the database, the last two parameter values are stored as 0. I have already converted the float variables to to NSStrings. I checked to make sure the values were correct before sending the post request through NSLog. However it is still showing up as zero. When I enter the form manually through my web browser with the exact same values, they are stored in the database.
My Post request looks like the following:
NSString *dateString = _date.text;
NSString *times = _time.text;
NSString *shape_illuminated = _shape.text;
NSString *orientation_illuminatedString = _orientation.text;
NSLog(#"compass is:%#%#", compassReceived, rollReceived);
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
NSURL * url = [NSURL URLWithString:#"http://example.com/mobile_app/submit.php"];
NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:url];
NSString * params = [NSString stringWithFormat:#"date=%#&time=%#&shape_illuminated=%#&orientation_illuminated=%#&=compass_direction=%#&=degreehorizon=%#", dateString, times, shape_illuminated, orientation_illuminatedString, compassReceived, rollReceived];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];
NSURLSessionDataTask * dataTask =[defaultSession dataTaskWithRequest:urlRequest
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(#"Response:%# %#\n", response, error);
if(error == nil)
{
NSString * text = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog(#"HttpReponseData = %#",text);
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Account error"
message:[NSString stringWithFormat:#"%#", dictionary]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
}];
[dataTask resume];
Some of the values from those NSLogs are:
compass is:127.0Angle:99.485866
In mysql I have the fields set up as floats.
Any ideas?
UPADATE:
I tried hard coding the values for compass_direction and degreehorizon and it still did not work.
UPDATE:
I have now tried properly configuring the url parameters using the following method:
-(NSString *)urlenc:(NSString *)val
{
CFStringRef safeString =
CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef)val,
NULL,
CFSTR("/%&=?$#+-~#<>|,.()[]{}^!"),
kCFStringEncodingUTF8);
return [NSString stringWithFormat:#"%#", safeString];
}
and then adding:
SString *query =
[NSString stringWithFormat:#"shape_illuminated=%#&orientation_illuminated=%#&=compass_direction=%#&=degreehorizon=%#",
[self urlenc:shape_illuminated],
[self urlenc:orientation_illuminatedString],
[self urlenc:convertedCompass],
[self urlenc:convertedRoll]];
NSLog(#"%#", query);
[urlRequest setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"content- type"];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:[query dataUsingEncoding:NSUTF8StringEncoding]];
but those two values are still not being sent. The output from the nslog looks fine to me. I even made a php form and entered the same values on my computer which works great, so I do not know what is going on here.

How to parse JSONP in Objective-C?

I am retrieving JSON information for an API and it says on the API that it is in JSON but I noticed it is in JSONP or "json with padding" as some call it. I tired to look everywhere to find how to parse this but no luck. The information I am trying to receive is this:
({"book":[{"book_name":"James","book_nr":"59","chapter_nr":"3","chapter":
{"16":{"verse_nr":"16","verse":"For where envying and strife is, there is confusion and
every evil work."}}}],"direction":"LTR","type":"verse"});
The link to the data is https://getbible.net/json?p=James3:16, so you can look at it directly.
This is the code I am using to try to retrieve the JSON Data and parse it into a NSMutableDictionary.
-(void)fetchJson {
NSString *currentURL = [NSString stringWithFormat:#"https://getbible.net/json?p=James"];
NSURL *url = [NSURL URLWithString:currentURL];
NSData *data = [[NSData alloc]initWithContentsOfURL:url];
NSURLRequest *theRequest = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60];
NSMutableData *receivedData = [[NSMutableData alloc] initWithLength:0];
NSURLConnection * connection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self startImmediately:YES];
[receivedData setLength:0];
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:url MIMEType:#".json" expectedContentLength:-1 textEncodingName:nil];
expectedTotalSize = [response expectedContentLength];
if ([data length] !=0) {
NSLog(#"appendingData");
[receivedData appendData:data];
if(connection){
NSLog(#"Succeeded! Received %lu bytes of data",(unsigned long)[receivedData length]);
}
NSError *error;
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
if(jsonResponse){
NSArray *responseArr = [jsonResponse mutableCopy];
NSLog(#"%lu",(unsigned long)[responseArr count]);
}else if (!jsonResponse){
//do internet connection error response
}
}
}
The results I am getting back from putting a breakpoint in the code is:
jsonResponse returns NULL
NSError NSCocoaErrorDomain code - 3840
but my NSData *data is returning 15640 bytes.
My console is displaying this from the NSLogs I used for debugging:
2014-04-20 01:27:31.877 appendingData
2014-04-20 01:27:31.879 Succeeded! Received 15640 bytes of data
I am receiving the data correctly but I am not parsing it correctly I know the error is because the JSON is in JSONP format. If anyone could please help with this I would appreciate it so much. I have tired to give as much detail on this question as I can but if you need more information just let me know so I can add it and make this as clear as possible.
Your code has at least two separate attempts to download the data. Neither is really correct. The code also only works with JSON, not JSONP.
Try this:
NSURL *url = [NSURL URLWithString:#"https://getbible.net/json?p=James"];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (data) {
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSRange range = [jsonString rangeOfString:#"("];
range.location++;
range.length = [jsonString length] - range.location - 2; // removes parens and trailing semicolon
jsonString = [jsonString substringWithRange:range];
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *jsonError = nil;
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&jsonError];
if (jsonResponse) {
// process jsonResponse as needed
} else {
NSLog(#"Unable to parse JSON data: %#", jsonError);
}
} else {
NSLog(#"Error loading data: %#", error);
}
}];
One problem is that the data you're downloading has extraneous information at the beginning and end. The JSON being delivered by your URL is:
({"book":[{"book_name":"James","book_nr":"59","chapter_nr":"3","chapter":{"16":{"verse_nr":"16","verse":"For where envying and strife is, there is confusion and every evil work."}}}],"direction":"LTR","type":"verse"});
As the error message you're seeing indicates: you need to remove the initial ( from the beginning of the string and the ); from the end so that your JSON will start with the dictionary that your code expects. You can do this by calling subdataWithRange: on your NSData object:
NSData* jsonData = [data subdataWithRange:NSMakeRange(1, data.length-3)];
NSDictionary* jsonResponse = [NSJSONSerialization JSONObjectWithData:jsonData
options:0
error:&error];
Just to update everyone, the NSURLRequest has been deprecated in iOS9. I tried the answer by #rmaddy, and I didn't receive anything either (just like what #lostAtSeaJoshua was encountering I guess). I have updated rmaddy's answer to reflect the NSURLSession implementation that has (I think) replaced NSURLRequest:
NSURLSession *session = [NSURLSession sharedSession];
NSURL *url = [NSURL URLWithString:#"http://somerandomwebsite.com/get.php?anotherRandomParameter=5"];
[[session dataTaskWithURL:url
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
// handle response
if (data) {
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"stringJSONed: %#",jsonString);
//Do something with the received jsonString, just like in # rmaddy's reply
} else {
NSLog(#"Error loading data: %#", error);
}
}] resume];
Just a heads up notice, when I first ran it, it gave me the security error. What you need to do (if you are using http) is to add this to your plist:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
I have to mention that after the NSAllowArbitraryLoads key, there are most probably other keys and values, such as NSExceptionDomain. But they're not really relevant to this answer I think. If you need to look further, let me know and I will dig deeper :)

simple mantle JSON example from URL

I have have some trouble in understanding what is needed to fetch a JSON file with mantle.h from a URL.
Can someone give me an example of how it works?
For example:
-I have a URL www.example.com with a JSONFile as follows:
{
"name": "michael"
}
How could I fetch it?
I use this process for fetching JSON:
NSURL *s = url;//Put your desird url here
NSURLRequest *requestURL = [NSURLRequest requestWithURL:s cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.00];
NSHTTPURLResponse *response;
NSError *error = [[NSError alloc]init];
NSData *apiData = [NSURLConnection sendSynchronousRequest:requestURL returningResponse:&response error:&error];
dictionaryData = [NSJSONSerialization JSONObjectWithData:apiData options:kNilOptions error:&error];
Now the dictionaryData contains your JSON. You can fetch it by:
NSString *name = [dictionaryData valueForKey:#"name"];
And make sure you are making async request. For this put the code within this block:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
//Put the code here
});
Hope this helps.. :)
Call it with following method
[super getRequestDataWithURL:urlString
andRequestName:sometext];
You will get response in the following method if successful
- (void)successWithRequest:(AFHTTPRequestOperation *)operation withRespose:(id)responseObject withRequestName:(NSString *)requestName {
NSString *response = operation.responseString;
id jsonObject = [response objectFromJSONString];
if(![super checkforServerRequestFailureErrorMessage:jsonObject]) {
[self.leaderboardProxyDelegate leaderboardListSuccessful:jsonObject];
}
}
You will get dictionary in jsonObject

Resources