I have a method which send request to server and i have created the call to that function with completionHandler as follows:
-(void)sendAddSubscriptionRequest:(NSString*)owner withComppletionHandler:(void (^)(BOOL, NSArray *, NSError *))completion
dataWebService = [[NSMutableData alloc] init];
NSURL* aUrl = [NSURL
URLWithString:[NSString stringWithFormat:#"https://www.google.com/add?"]];
NSMutableURLRequest* request =
[NSMutableURLRequest requestWithURL:aUrl
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:30.0];
[request addValue:[NSString stringWithFormat:#"Bearer %#", "token"]
forHTTPHeaderField:#"Authorization"];
[request setHTTPMethod:#"POST"];
NSString* postData =
[[NSString alloc] initWithFormat:#"owner=%#",
owner];
[request setHTTPBody:[postData dataUsingEncoding:NSUTF8StringEncoding]];
NSData* returnData = [NSURLConnection sendAsynchronousRequest:request queue:nil completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
};
My problem is how should i return completion handler to my function after the data is fetched.
Thanks,.
As you are sending an asynchronous request, the method will return immediately as the data will be "returned" in the NSURLConnection completion handler. You can then decode it there and pass it along to your own completion handler:
[NSURLConnection sendAsynchronousRequest:request
queue:nil
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSArray *array = nil;
if (!connectionError)
array = /* get from data somehow */
completion(!connectionError, array, connectionError);
}];
Note: It's not clear what your completion handler parameters mean, so I might have taken some liberties.
Related
I have this code;
NSString *post = [NSString stringWithFormat:#"latitude=%lf&longitude=%lf&provider=network&accuracy=%lf&hiz=%lf&retrieveTime=%#",
locationManager.location.coordinate.latitude,
locationManager.location.coordinate.longitude,
locationManager.location.horizontalAccuracy,
locationManager.location.speed,
dateString];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%lu", [postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
NSString *sUrl = [[NSUserDefaults standardUserDefaults] stringForKey:#"serviceUrl"];
NSString *swoclString = [NSString stringWithFormat:#"%#/saveLocation.php", sUrl];
[request setURL:[NSURL URLWithString:swoclString]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Type"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if(conn) {
NSLog(#"Location Save Successfully");
} else {
NSLog(#"Location Save Error");
}
I can receive the data in the server side. And on the iOS side I can see the log "Location Save Successfully".
How can I receive the response from the server without implementing other methods?
Use NSURLSession instead of NSURLConnection to post your data to the Server. Below is an example how you can post JSON.
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:nil delegateQueue:nil];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"<YOUR-URL-STRING>"] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:120.0];
[request setHTTPMethod:#"POST"];
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request addValue:#"application/json" forHTTPHeaderField:#"Accept"];
NSError *error;
NSData *postData = [NSJSONSerialization dataWithJSONObject:<YOUR_JSON_DATA> options:NSJSONWritingPrettyPrinted error:&error];
NSString *tmp = [[NSString alloc]initWithData:postData encoding:NSUTF8StringEncoding];
[request setHTTPBody:postData];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSHTTPURLResponse *resp = (NSHTTPURLResponse *) response;
NSLog(#"%li",(long)resp.statusCode);
if(resp.statusCode==200){
NSMutableArray *result = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&jsonError];
}];`
The block is used to return the response by the server. For example the HTTP-Status Code and the response data. If you use json you can convert the Data with the NSJSONSerialization class.
If you are using latest ios coding standards you must have to use URLSession object to send any request to the API calls because DEPRECATED: The NSURLConnection class should no longer be used. NSURLSession is the replacement for NSURLConnection. But still, if you want to continue with an old procedure, there are three ways to send API request.
P1:
-(void)procedure1{
NSURLRequest *requestObject = nil; /** replace with your request object **/
NSURLResponse *serverResponse = nil;
NSError *connectError = nil;
/* thread bloker request */
NSData *responseData = [NSURLConnection sendSynchronousRequest:requestObject returningResponse:&serverResponse error:&connectError];
if (connectError == nil) {
//parse server response data (i.e, json or xml)
}else{
/* handle connection error */
}
}
P2:
-(void)procedure2{
NSURLRequest *requestObject = nil; /** replace with your request object **/
/* thread free request */
[NSURLConnection sendAsynchronousRequest:requestObject queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
if (connectionError == nil) {
//parse server response data (i.e, json or xml)
}else{
/* handle connection error */
}
}];
}
P3:
the last one is a bit different than the other two,
#interface TestViewController ()<NSURLConnectionDelegate>
#property (nonatomic, retain) NSMutableData* responseData;
#end
-(void)procedure3{
NSURLRequest *requestObject = nil; /** replace with your request object **/
NSURLConnection *connectionObject = [NSURLConnection connectionWithRequest:requestObject delegate:self];
[connectionObject start];
}
here in this procedure you are required to invoke NSURLConnectionDelegate methods
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[self.responseData setLength:0];
}
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.responseData appendData:data];
}
- (void) connectionDidFinishLoading:(NSURLConnection *)connection {
NSString* responseString = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
connection = nil;
}
I have
NSString* FBAuthoValue= #"TESTINGCONSTANT";
On click of Load Button ,it call HitLoadAPI
I am calling my API like below HitLoadAPI, now if at my server end my FBAuthoValue is change i need to Hit another API to get refresh value of FBAuthoValue, and set in HitLoadAPI.
1) User hit HitLoadAPI with FBAuthoValue= #"TESTINGCONSTANT" value, but as in server now FBAuthoValue= #"NewTestCode", so it return httpresponsecode 909,on 909 i need to call refreshFBAuthValue api, and put this value back to HitLoadAPI, and the api work correctly.
2) if FBAuthoValue token change in server, need to call refreshFBAuthValue API, and its return value need to set and call the HitLoadAPI again,without knowing the user.
NOTE: i have to hit multiple API one after another, suppose API-1,API-2,API-3 and so on, and if FBAuthoValue, if in any api ,changes in server then need to refresh that FBAuthoValue and then the same API need to be call, without effecting or blocking to user.
I will reward 50 bounty for sure.
Overview: API-1 call, in the meanwhile if token expire,need to call token expire api, and the API-1 will recall again, without user press Load Button again.
Here is my code
-(void)HitLoadAPI
{
NSError *error;
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
NSURL *url = [NSURL URLWithString:#"[JSON SERVER"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request addValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setHTTPMethod:#"POST"];
[request setValue:FBAuthoValue forHTTPHeaderField:FBAUTH];
NSDictionary *mapData = [[NSDictionary alloc] initWithObjectsAndKeys: #"TEST IOS", #"name",
#"IOS TYPE", #"typemap",
nil];
NSData *postData = [NSJSONSerialization dataWithJSONObject:mapData options:0 error:&error];
[request setHTTPBody:postData];
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary* headers = [(NSHTTPURLResponse *)response allHeaderFields];
//NSLog(#" headers =%#",headers);
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
//NSLog(#"response status code: %ld", (long)[httpResponse statusCode]);
if([httpResponse statusCode]==909)
{
FBAuthoValue =[self refreshFBAuthValue];
//what to do here so the current API hit will be call again....
}
}];
[postDataTask resume];
}
-(NSString *) refreshFBAuthValue
{
//hit api to get new refresh token code here need its calling code as well as the block coding cause it response so late which cause return value nil...to HitLoadAPI
return FBaccess_token; //it will return refresh FBaccess_token code
}
You can create a method which you can use to call any api from anywhere in the application, This method takes the parameter specific to an api call, like api url, data which will be included in the body of the request and a completion block which will be called when fbAuthValue is valid.
-(void)HitAPILoadWithFbAuthValue:(NSString*)fbAuthValue apiUrl:(NSString*)apiUrl postData:(NSDictionary*)dict withCompletion:(void (^)(int statusCode,NSURLResponse * apiResponse,NSError * error))completion{
NSError *error;
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
NSURL *url = [NSURL URLWithString:apiUrl];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request addValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setHTTPMethod:#"POST"];
[request setValue: fbAuthValue forHTTPHeaderField:FBAUTH];
//post body with dictionary passed as a parameter
NSData *postData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
[request setHTTPBody:postData];
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary* headers = [(NSHTTPURLResponse *)response allHeaderFields];
//NSLog(#" headers =%#",headers);
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
//NSLog(#"response status code: %ld", (long)[httpResponse statusCode]);
if([httpResponse statusCode]==909)
{
FBAuthoValue =[self refreshFBAuthValue];
//what to do here so the current API hit will be call again....
if (FBAuthoValue){
[self HitAPILoadWithFbAuthValue:fbAuthValue apiUrl:apiUrl postData:dict withCompletion:completion];
}else{
}
}
//if FbAuthValue is valid, call completion block
completion((int)[httpResponse statusCode],response, error);
}];
[postDataTask resume];
}
Usage
I assume you write this method in a separate class called APIManager. So to call this method first create an instance of the APIManager and call like this:
APIManager *sharedManager = [APIManager sharedInstance]
//call API_1
[sharedManager HitAPILoadWithFbAuthValue:FBAuthValue apiUrl:#"API_1_URL" postData:dict_for_first_api withCompletion:^(int statusCode, NSURLResponse *apiResponse, NSError *error) {
if(error != nil){
//handle error here
}else{
//call API_2
[sharedManager HitAPILoadWithFbAuthValue:FBAuthValue apiUrl:#"API_2_URL" postData:dict_for_second_api withCompletion:^(int statusCode, NSURLResponse *apiResponse, NSError *error) {
}];
}
}];
NSError *error = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSOperationQueue *downloadOperationQueue = [[NSOperationQueue alloc] init];
[downloadOperationQueue cancelAllOperations];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:Url]];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:jsonData];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue currentQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
NSLog(#"Respose %#",response.URL);
NSString *jsonInString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"json in string for backend: %#",jsonInString);
[self.delegate responseConnection:data withMethodName:methodName];
if (!error)
{
// did finish logic here, then tell the caller you are done with success
// completion(YES, nil);
}
else
{
// otherwise, you are done with an error
// completion(NO, error);
}
}];
For NSURLSession:
You can use [NSURLSession cancelPreviousPerformRequestsWithTarget:self];
For NSURLConnection also
You can use [NSURLConnection cancelPreviousPerformRequestsWithTarget:self];
I am fetching data using POST method. And I have successfully retrieved all the data.It's taking too long to display it in UI but I can print it immediately on console, my code is
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"http://www.xxxyyy.com/v1/api/client/authorize"]];
[request setHTTPMethod:#"POST"];
[request setValue:#"ABCD" forHTTPHeaderField:#"Authkey"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
[[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
NSString *requestReply = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
[request setValue:#"application/json;charset=UTF-8" forHTTPHeaderField:#"Authkey"];
NSData* data1 = [requestReply dataUsingEncoding:NSUTF8StringEncoding];
jsonReturnArray = [NSJSONSerialization JSONObjectWithData:data1 options:NSJSONReadingAllowFragments error:&error];
NSArray *array = [jsonReturnArray copy];
[self rec:array];
NSString *phoneNumber=[NSString stringWithFormat:#"%#",[jsonReturnArray valueForKey:#"phone"]];
lblPhoneNumber.text = phoneNumber;
NSString *Address=[NSString stringWithFormat:#"%# %# %#,CA %#",[jsonReturnArray valueForKey:#"street1"],[jsonReturnArray valueForKey:#"street2"],[jsonReturnArray valueForKey:#"city"],[jsonReturnArray valueForKey:#"postalcode"]];
lblAddress.text=Address;//takes long time to display
NSLog(#"%#",Address);//immeaditely print
strlatitude=[jsonReturnArray valueForKey:#"latitude"];
strlongitude=[jsonReturnArray valueForKey:#"longitude"];
[self Map:(MKMapView *)mapLocation didUpdateUserLocation:(MKUserLocation *)nil];//method call
}] resume];
This is take too time to print data, but if you use NSURLConnection class it may be help you.This is my Class method it may be helpful.
+ (void)postRequestData:(NSDictionary *)postVars
Action:(APIMode)action
WithCompletionHandlar:(void (^) (id result, BOOL status))completionBlock
{
NSURL *url = [NSURL URLWithString:API_URL([self getAPINameForType:action])];
NSLog(#"Request URL %#",[NSString stringWithFormat:#"%#",url]);
NSString *contentType = #"application/json";
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
[request addValue:contentType forHTTPHeaderField: #"Content-Type"];
NSError *err = nil;
NSMutableDictionary *params=[[NSMutableDictionary alloc] initWithDictionary:postVars];
// [params setObject:[self getAPINameForType:action] forKey:#"mode"];
NSLog(#"Paramater %#",params);
NSData *body = [NSJSONSerialization dataWithJSONObject:params options:NSJSONWritingPrettyPrinted error:&err];
[request setHTTPBody:body];
[request addValue:[NSString stringWithFormat:#"%lu", (unsigned long)body.length] forHTTPHeaderField: #"Content-Length"];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError)
{
if(!connectionError)
{
NSError *error = nil;
NSDictionary *dictResponse = [NSDictionary dictionaryWithDictionary:[NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingAllowFragments error:&error]];
dispatch_async(dispatch_get_main_queue(), ^{
completionBlock(dictResponse,(error == nil));
});
NSLog(#"%#",dictResponse);
}
else
{
dispatch_async(dispatch_get_main_queue(), ^{
completionBlock(connectionError.localizedDescription,NO);
});
}
}];
}
Use this method instead of it.It is executed fast because NSURLConnection Class execute in background.
Try to fetch your data using NSURLConnection class(manual code) or simply use AFNetworking class(less code). AFNetworking internally uses NSURLConnection class itself.
This is my json Dictionary
{"pid":"14982","type":"intervention","uid":"10008","bookmark_g7l03":{"und":[{"value":"S:1","format":"null","safe_value":"S:1"}]}}
I need to pass the PUT request to the following URL
http://example.com/services/profiles/pid
Let us know how to pass the dictionary to Webservice URL in IOS
NSString *data = [NSString stringWithFormat:#"{\"pid\":\"%#\",\"type\":\"%#\",\"uid\":\"%#\",\"%#\":{\"und\":\[{\"value\":\"%#\",\"format\":\"null\",\"safe_value\":\"\%#\"}]}}",pid,type, uidNo,bkMarkStr,self.startString,self.startString];
NSURL *bkMrkUrl = [NSURL URLWithString:#"http://example.com/services/profiles/pid=14997"];
NSData *postData = [data dataUsingEncoding:NSUTF8StringEncoding];
NSMutableURLRequest *bkMrkReq = [[NSMutableURLRequest alloc]initWithURL:bkMrkUrl];
[bkMrkReq setHTTPMethod:#"PUT"];
[bkMrkReq setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[bkMrkReq setHTTPBody:postData];
[NSURLConnection sendAsynchronousRequest:bkMrkReq queue:[NSOperationQueue currentQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSString *txt = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSLog(#"data....:%#",txt);
// handle response here
}];
Here, When i Print the text data
Output is: <?xml version="1.0" encoding="utf-8"?>
<result>CSRF validation failed</result>
What should i do with the data..
Here am updating the fields info in server.
You can try:
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://example.com/services/profiles/pid"]];
[request setHTTPMethod:#"PUT"];
NSString *params = #"\{\"pid\" : \"14997\", \"type\" : \"intervention\", \"uid\" : \"10046\"}"; // The rest of your parmas here
[request setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue currentQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
// handle response here
}];
If you want to make the request synchronously instead you can use:
NSURLResponse *response;
NSError *error;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];