I use the following code to create a dictionary based on a JSON string received from the server. (I have downloaded JSONKit and embedded it into the project). The code below returns a legal JSON string from the server (parsed well on Android) but crashes when I try to convert it to a dictionary.
- (IBAction)submit
{
bool useSSL = true;
char *c_url="http://(rest of URL)";
NSString* url = [NSString stringWithFormat:#"%s" , c_url];
url = [NSString stringWithFormat:#"%#%#%s", url, self.label.text, "/keys"];
NSString * response = [self getDataFrom:url];
NSDictionary *dict = [response objectFromJSONString]; //generates SIGABRT!!
NSLog(#"%#",dict);
NSString *success = [dict valueForKey:#"success"];
}
- (NSString *) getDataFrom:(NSString *)url{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setHTTPMethod:#"GET"];
[request setURL:[NSURL URLWithString:url]];
NSError *error = [[NSError alloc] init];
NSHTTPURLResponse *responseCode = nil;
NSData *oResponseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&responseCode error:&error];
if([responseCode statusCode] != 200){
NSLog(#"Error getting %#, HTTP status code %i", url, [responseCode statusCode]);
return nil;
}
return [[NSString alloc] initWithData:oResponseData encoding:NSUTF8StringEncoding];
}
THANKS,
Simon
Found an answer here.
Answer says: "Figured it out... I had JSONKIt.h included in the project but for some weird reason, JSONKit.m was not included in the 'Compile Sources' under 'Build Phases' - once I added it manually it started working fine."
Related
I have created a small project that can read and insert data from iPhone to sql server via RESTful WCF service.
I have read the data successfully with the following approach:
1- I have created a wcf web service that read data from Sql serverwith table Employees(firstname,lastname,salary):
"41.142.251.142/JsonWcfService/GetEmployees.svc/json/employees"
2- I have created a new project in xcode 5.0.2, and I added a textfield (viewData.text) to display data retrieved by the web service.
3- I added the following instruction in my viewController.m :
"#define WcfSeviceURL [NSURL URLWithString: #"41.142.251.142/JsonWcfService/GetEmployees.svc/json/employees"]"
3- In (void)viewDidLoad method, I implemented the below code:
- (void)viewDidLoad
{
[super viewDidLoad];
NSError *error = nil;
NSData *data = [NSData dataWithContentsOfURL:WcfSeviceURL options:NSDataReadingUncached error:&error];
if(!error)
{
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:data
options:NSJSONReadingMutableContainers
error:&error];
NSMutableArray *array= [json objectForKey:#"GetAllEmployeesMethodResult"];
for(int i=0; i< array.count; i++)
{
NSDictionary *empInfo= [array objectAtIndex:i];
NSString *first = [empInfo objectForKey:#"firstname"];
NSString *last = [empInfo objectForKey:#"lastname"];
NSString *salary = [empInfo objectForKey:#"salary"];
//Take out whitespaces from String
NSString *firstname = [first
stringByReplacingOccurrencesOfString:#" " withString:#""];
NSString *lastname = [last
stringByReplacingOccurrencesOfString:#" " withString:#""];
viewData.text= [viewData.text stringByAppendingString:[NSString stringWithFormat:#"%# %# makes $%#.00 per year.\n",firstname,lastname,salary]];
}
}
}
Check the following link : http://www.codeproject.com/Articles/405189/How-to-access-SQL-database-from-an-iPhone-app-Via.
As I mentioned, I can read the data from my iPhone without any problem.
So the second step is how to write and insert data from the iPhone to sql server.
for this, I created first the method that insert data in my webservice:
In WCF interface:
[OperationContract]
[WebInvoke(Method = "POST",
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "json/InsertEmployee/{id1}/{id2}/{id3}")]
bool InsertEmployeeMethod(string id1,string id2, string id3);
In Implementation:
public bool InsertEmployeeMethod(string id1,string id2, string id3)
{
int success = 0;
using (SqlConnection conn = new SqlConnection("server=(local);database=EmpDB;Integrated Security=SSPI;"))
{
conn.Open();
decimal value= Decimal.Parse(id3);
string cmdStr = string.Format("INSERT INTO EmpInfo VALUES('{0}','{1}',{2})",id1,id2,value);
SqlCommand cmd = new SqlCommand(cmdStr, conn);
success = cmd.ExecuteNonQuery();
conn.Close();
}
return (success != 0 ? true : false);
}
So to test this web servcie method use:
"41.142.251.142/JsonWcfService/GetEmployees.svc/json/InsertEmployee/myName/MylastName/6565"
Then to consume this method from iPhone I used the following approach:
I decalared the Define Instruction:
"#define BaseWcfUrl [NSURL URLWithString:
#"41.142.251.142/JsonWcfService/GetEmployees.svc/json/InsertEmployee/{id1}/{id2}/{id3}"]"
Then I implemented the Insert Employee Method related to click button.
-(void) insertEmployeeMethod
{
if(firstname.text.length && lastname.text.length && salary.text.length)
{
NSString *str = [BaseWcfUrl stringByAppendingFormat:#"InsertEmployee/%#/%#/%#",firstname.text,lastname.text,salary.text];
NSURL *WcfServiceURL = [NSURL URLWithString:str];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:WcfServiceURL];
[request setHTTPMethod:#"POST"];
// connect to the web
NSData *respData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
// NSString *respStr = [[NSString alloc] initWithData:respData encoding:NSUTF8StringEncoding];
NSError *error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:respData
options:NSJSONReadingMutableContainers
error:&error];
NSNumber *isSuccessNumber = (NSNumber*)[json objectForKey:#"InsertEmployeeMethodResult"];
//create some label field to display status
status.text = (isSuccessNumber && [isSuccessNumber boolValue] == YES) ? [NSString stringWithFormat:#"Inserted %#, %#",firstname.text,lastname.text]:[NSString stringWithFormat:#"Failed to insert %#, %#",firstname.text,lastname.text];
}
}
But the issue here, is in the following instruction:
NSString *str = [BaseWcfUrl stringByAppendingFormat:#"InsertEmployee/%#/%#/%#",firstname.text,lastname.text,salary.text];
Always the system returns a message 'Data parameter nil' with this line, knowing that the firstname.text, and lastname.text, salary are all filled and I can see their values with NSLog(#"First Name :%#",firstname.text)...
Can you please help on this?
Thanks in advance.
I don't think NSURLs stringByAppendingFormat will do what you want.
Try something like this:
#define kBase_URL #"41.142.251.142/JsonWcfService/GetEmployees.svc/json/%#"
#define kAuthAPI_InsertEmployee_URL [NSString stringWithFormat:kBase_URL, #"InsertEmployee/%#/%#/%#"]
//Setup session
NSError *error;
NSURL *requestURL = [NSURL URLWithString:[NSString stringWithFormat:kAuthAPI_InsertEmployee_URL,firstname.text,lastname.text,salary.text]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request addValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setHTTPMethod:#"POST"];
NSData *postData = [NSJSONSerialization dataWithJSONObject:profileData options:0 error:&error];
[request setHTTPBody:postData];
etc. etc.
I am working with an application where I have to request a url and I get the response accordingly
I am using ASIHTTPRequest to request the URL
here is my request
-(void)getTips {
if ([CommonFunctions networkConnected]) {
ShowNetworkActivityIndicator();
NSString *strPhp = #"staticpage.php";
NSString *strQuery = [[NSString alloc] initWithString:[NSString stringWithFormat:#"%#%#?static_id=3",GMS_URL,strPhp]];
ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:strQuery]];
NSLog(#"tips url %#",request.url);
request.delegate = self;
[request setRequestMethod:#"GET"];
[request startAsynchronous];
}
}
These are my delegate methods
-(void)request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data {
// NSString *responseStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// NSLog(#"responseStr %#",responseStr);
SBJsonParser *json = [[SBJsonParser alloc]init];
NSLog(#"json data %#",[json objectWithData:data]);
NSMutableArray *marrData = [[json objectWithData:data] valueForKey:#"responseData"];
if([[marrData valueForKey:#"result"] isEqualToString:#"failed"]){
[CommonFunctions showAlertMessage:[marrData valueForKey:#"error"]];
}
HideNetworkActivityIndicator();
}
Here I get null data no matter whether I pass request methods GET or POST
When I check the same url in browser I get the response and a valid json from online json viewer
What are the possible reason that I am getting null data in the application
Use requestFinished: delegate.. Please try this.
-(void)requestFinished:(ASIHTTPRequest *)request
{
NSLog(#"response %#", [request responseString]);
}
I have seen that most data in iOS is in either JSON or XML. I was interested to know whether there is any third party library or wrapper class that tackles both types of data and responses accordingly. I know I could use for example JSONKit for JSON data and NSXMLParser for XML. But i looking for one that tackles both.
Is there any such wrapper?
Welcome to any suggestions and guidance. Thanks.
I think It's support to JSON /XML,just can you change some line.
NSString *str1=#"type url";
NSString *poststr1 = [NSString stringWithFormat:#"%#",str1];
NSString *posturl1=[NSString stringWithFormat:#" your url json/xml"];
// NSLog(#"city url name %#",posturl1);
NSURL *url=[NSURL URLWithString:[NSString stringWithFormat:#"%#",posturl1]];
NSData *postData1 = [poststr1 dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData1 length]];
NSMutableURLRequest *request =[[[NSMutableURLRequest alloc] init] autorelease];
[request setHTTPBody:postData1];
[request setURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
NSError *error;
NSURLResponse *response;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
// NSString *data=[[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];//this line supprted to json
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:urlData
options:kNilOptions
error:&error];//this line supported to xml
NSLog(#"json %#",json);
//NSDictionary*results = [data JSONValue];//this line supported to JSON
//NSLog(#"results json----->%#",results);
AFNetworking will do both, and has a goot reputation, for example see the Ray Wenderlich site which has lots of other useful information too.
I have created one wrapper class for json. In there, I have created one method given below, I think it will help you.
Parse Method:
-(void)jsonDeserialize:(NSString *)key fromDict:(id)content completionHandler:(void (^) (id parsedData, NSDictionary *fromDict))completionHandler{
if (key==nil && content ==nil) {
completionHandler(nil,nil);
}
if ([content isKindOfClass:[NSArray class]]) {
for (NSDictionary *obj in content) {
[self jsonDeserialize:key fromDict:obj completionHandler:completionHandler];
}
}
if ([content isKindOfClass:[NSDictionary class]]) {
id result = [content objectForKey:key];
if ([result isKindOfClass:[NSNull class]] || result == nil) {
NSDictionary *temp = (NSDictionary *)content;
NSArray *keys = [temp allKeys];
for (NSString *ikey in keys) {
[self jsonDeserialize:key fromDict:[content objectForKey:ikey] completionHandler:completionHandler];
}
}else{
completionHandler(result,content);
}
}
}
Method Call:
NSData *content = [NSData dataWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"Sample" ofType:#"json"]];
NSError *error;
//to get serialized json data...
id dictionary = [NSJSONSerialization JSONObjectWithData:content options:NSJSONReadingMutableContainers error:&error];
//get data for key called GetInfo
[self jsonDeserialize:#"GetInfo" fromDict:dictionary completionHandler:^(id parsedData, NSDictionary *fromDict) {
NSLog(#"%# - %#",parsedData,fromDict);
}];
My App_Code/IGetEmployees.vb file
<ServiceContract()> _
Public Interface IGetEmployees
<OperationContract()> _
<WebInvoke(Method:="POST", ResponseFormat:=WebMessageFormat.Json, BodyStyle:=WebMessageBodyStyle.Wrapped, UriTemplate:="json/contactoptions")> _
Function GetAllContactsMethod(strCustomerID As String) As List(Of NContactNames)
End Interface
My App_Code/GetEmployees.vb file
<WebMethod()> _
<ScriptMethod(ResponseFormat:=ResponseFormat.Json)> _
Public Function GetAllContactsMethod(strCustomerID As String) As List(Of NContactNames) Implements IGetEmployees.GetAllContactsMethod
Utilities.log("Hit get all contacts at 56")
Dim intCustomerID As Integer = Convert.ToInt32(strCustomerID)
Dim lstContactNames As New List(Of NContactNames)
'I add some contacts to the list.
Utilities.log("returning the lst count of " & lstContactNames.Count)
Return lstContactNames
End Function
NContactNames is a class with 3 properties.
So i am using ASP.NET web services to retrieve information from SQL server and pass it to my iPad in JSON format. I have a problem with parameter passing. So like you see i have 2 files IGetEmployees.vb and GetEmployees.vb. I am implementing the method GetAllContactsMethod. What's happening is the two lines in GetEmployees.vb file (Utilities.log), they never get logged. The function is not getting called at all.
My objective c code to call this function
NSString *param = [NSString stringWithFormat:#"strCustomerID=%#",strCustomerID];
jUrlString = [NSString stringWithFormat:#"%#",#"http://xyz-dev.com/GetEmployees.svc/json/contactoptions"];
jurl = [NSURL URLWithString:jUrlString];
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:jurl];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[param dataUsingEncoding:NSUTF8StringEncoding]];
NSLog(#" request string is %#",[[request URL] absoluteString]);
NSLog(#"Done");
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:request delegate:self];
if(theConnection)
{
jData = [NSMutableData data];
NSError *jError;
NSMutableDictionary *json =[NSJSONSerialization JSONObjectWithData:jData options:kNilOptions error:&jError];
NSLog(#"%#",json); //Gets Here and prints (null)
NSLog(#"Done"); //prints this as well.
}
else
{
NSLog(#"No");
}
At the time of posting this code the "if" statement is true and (null) is printed followed by "Done"
The output of my absolute request is:
request string is http://xyz-dev.com/GetEmployees.svc/json/contactoptions
This is the first time i am writing json to accept parameters. So i might be missing something.What is it?Why is the function not getting called at all on the Visual Studio side. If you need more info please ask.Thanks...
this is the moethod in Objetive-C, for that.
-(void) insertEmployeeMethod
{
if(firstname.text.length && lastname.text.length && salary.text.length)
{
NSString *str = [BaseWcfUrl stringByAppendingFormat:#"InsertEmployee/%#/%#/%#",firstname.text,lastname.text,salary.text];
NSURL *WcfSeviceURL = [NSURL URLWithString:str];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:WcfSeviceURL];
[request setHTTPMethod:#"POST"];
// connect to the web
NSData *respData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
// NSString *respStr = [[NSString alloc] initWithData:respData encoding:NSUTF8StringEncoding];
NSError *error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:respData
options:NSJSONReadingMutableContainers
error:&error];
NSNumber *isSuccessNumber = (NSNumber*)[json objectForKey:#"InsertEmployeeMethodResult"];
//create some label field to display status
status.text = (isSuccessNumber && [isSuccessNumber boolValue] == YES) ? [NSString stringWithFormat:#"Inserted %#, %#",firstname.text,lastname.text]:[NSString stringWithFormat:#"Failed to insert %#, %#",firstname.text,lastname.text];
}
}
Before to run the code, test your URL with POSTMAN, is an app from Google Chrome.
regards.
am starting to build login form reading from external server via http request i need to parse json result to get user name
- (IBAction)getlogin:(UIButton *)sender {
NSString *rawStrusername = [NSString stringWithFormat:#"username=%#",_username.text];
NSString *rawStrpassword = [NSString stringWithFormat:#"password=%#",_password.text];
NSString *post = [NSString stringWithFormat:#"%#&%#", rawStrusername, rawStrpassword];
// NSString *post = #"rawStrusername&rawStrpassword";
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
/* NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]]; */
NSURL *url = [NSURL URLWithString:#"http://www.othaimmarkets.com/my_services_path/user/login.json"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
/* [request setValue:postLength forHTTPHeaderField:#"Content-Length"]; */
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSURLResponse *response;
NSError *err;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];
NSLog(#"responseData: %#", [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]);
//NSLog(#"responseData: %#", responseData);
}
I get this result:
{"sessid":"g2ev7til6d750ducrkege0cbj2","session_name":"SESS02795057fe9e6b2fc0777bf4057b248f","user":{"uid":"617","name":"mohammed.abdelrasoul#gmail.com","mail":"mohammed.abdelrasoul#gmail.com","mode":"0","sort":"0","threshold":"0","theme":"","signature":"","signature_format":"0","created":"1316602317","access":"1352643854","login":"1352666338","status":"1","timezone":"10800","language":"ar","picture":"","init":"mohammed.abdelrasoul#gmail.com","data":"a:5:{s:18:\"country_iso_code_2\";s:2:\"SA\";s:13:\"timezone_name\";s:11:\"Asia/Riyadh\";s:5:\"block\";a:1:{s:7:\"webform\";a:1:{s:15:\"client-block-88\";i:1;}}s:13:\"form_build_id\";s:37:\"form-3ae73833f08accc7abe5517347ea87eb\";s:7:\"contact\";i:0;}","country_iso_code_2":"SA","timezone_name":"Asia/Riyadh","block":{"webform":{"client-block-88":1}},"form_build_id":"form-3ae73833f08accc7abe5517347ea87eb","contact":0,"roles":{"2":"authenticated user"}}}
Or, formatted for the sake of legibility:
{
"sessid":"g2ev7til6d750ducrkege0cbj2",
"session_name":"SESS02795057fe9e6b2fc0777bf4057b248f",
"user":{
"uid":"617",
"name":"mohammed.abdelrasoul#gmail.com",
"mail":"mohammed.abdelrasoul#gmail.com",
"mode":"0",
"sort":"0",
"threshold":"0",
"theme":"",
"signature":"",
"signature_format":"0",
"created":"1316602317",
"access":"1352643854",
"login":"1352666338",
"status":"1",
"timezone":"10800",
"language":"ar",
"picture":"",
"init":"mohammed.abdelrasoul#gmail.com",
"data":"a:5:{s:18:\"country_iso_code_2\";s:2:\"SA\";s:13:\"timezone_name\";s:11:\"Asia/Riyadh\";s:5:\"block\";a:1:{s:7:\"webform\";a:1:{s:15:\"client-block-88\";i:1;}}s:13:\"form_build_id\";s:37:\"form-3ae73833f08accc7abe5517347ea87eb\";s:7:\"contact\";i:0;}",
"country_iso_code_2":"SA",
"timezone_name":"Asia/Riyadh",
"block":{
"webform":{
"client-block-88":1
}
},
"form_build_id":"form-3ae73833f08accc7abe5517347ea87eb",
"contact":0,
"roles":{
"2":"authenticated user"
}
}
}
how i can get the objects data or parse the result to get user name
any help or examples will be appreciated
You need to use the NSJSONSerialization class method, JSONObjectWithData:options:error: to create an NSDictionary:
NSError *error;
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:&error];
if (! error) {
NSLog(#"%#",jsonDict);
}else{
NSLog(#"%#",error.localizedDescription);
}
This will get you to the point where you can look at the dictionary, which will be easier to read. It looks like you need to use objectForKey:#"sessid" to get you to user, then objectForKey#"user", then objectForKey:#"name" to get you to the name.
Check out this framework for parsing json. https://github.com/stig/json-framework/
Also check out this answer iPhone/iOS JSON parsing tutorial. You'll find a link to a tutorial you can do to get acquainted with json parsing in ios.
See this answer and some code :
NSMutableData *data; // Contains data received from the URL connection declares in header
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)dataIn
{
// Do it this way because connection doesn't guarantee all the data is in
POLLog(#" Tide View connection");
[data appendData:dataIn];
}
- (void) connectionDidFinishLoading:(NSURLConnection *) conn
{
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSDictionary *results = [jsonString JSONValue]; // This is a new category added to the NSString by SBJSON
//100 parameters
for (int n=0;n<=100;n++)
{
// Get all the returned results
params[n] = [[results objectForKey:[NSString stringWithFormat:#"param%d",n]] floatValue];
}
To expand upon rdelmar's answer (which I think you should accept), you can use NSJSONSerialization and then navigate the NSDictionary results to extract the userName:
NSError *error;
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:responseData
options:0
error:&error];
if (error == nil) {
NSDictionary *userDictionary = [jsonDict objectForKey:#"user"];
NSString *userName = [userDictionary objectForKey:#"name"];
// do what you need with the userName
} else {
NSLog(#"%#",error.localizedDescription);
}
Or if using the latest version of Xcode, you can replace those objectForKey references with the even more concise Modern Objective-C syntax:
NSDictionary *userDictionary = jsonDict[#"user"];
NSString *userName = userDictionary[#"name"];