I am a beginner in handling connections in iOS. I want to perform a POST request and a GET request to a url. The thing is that I need to first do the POST so I can get an access token parsed in a JSON that later will place in the header of the GET request, so I can retrieve the login data I need. I am using custom delegate methods, but when I run this, the GET request is performed earlier than the POST, so I cannot get the key before the GET is done. Is there any way to perform the POST first and then the GET? Here is my code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
//params
self.user = #"carlos";
self.pass = #"1234";
self.grantType = #"password";
self.clientId = #"7da713e69afc96cf894e";
self.clientSecret = #"2c14ec54cfdfd6faec4ef56ca7f0870ab83f820b";
// Set the side bar button action. When it's tapped, it'll show up the sidebar.
self.sideBarButton.target = self.revealViewController;
self.sideBarButton.action = #selector(revealToggle:);
// Set the gesture
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
[self httpPostWithCustomDelegate];
[self sendHTTPGet];
}
-(void) httpPostWithCustomDelegate
{
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
NSURL * url = [NSURL URLWithString:#"http://192.237.241.175:8090/oauth2/access_token/"];
NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:url];
NSString * params =[NSString stringWithFormat:#"&username=%#&password=%#&grant_type=%#&client_id=%#&client_secret=%#&scope=write",self.user,self.pass,self.grantType,self.clientId,self.clientSecret];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];
NSURLSessionDataTask * dataTask =[defaultSession dataTaskWithRequest:urlRequest
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(#"Retrieving Data");
// NSLog(#"Response:%# %#\n", response, error);
if(error == nil)
{
//Test Display
// NSString * text = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
// NSLog(#"Data = %#",text);
self.responseDataPost = [[NSMutableData alloc] init];
[self.responseDataPost appendData:data];
NSError *error;
NSMutableDictionary *receivedData = [NSJSONSerialization JSONObjectWithData:self.responseDataPost options:NSJSONReadingMutableContainers error:&error];
//obtener del dictionary el access token y meter como header Authorization Bearer + id
//NSArray *accessToken = [receivedData valueForKeyPath:#"access_token"];
self.connTxtPost.text = [receivedData valueForKeyPath:#"access_token"];
self.recData = [receivedData valueForKeyPath:#"access_token"];
}
}];
[dataTask resume];
}
-(void) sendHTTPGet
{
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: self delegateQueue: [NSOperationQueue mainQueue]];
NSURL * url = [NSURL URLWithString:#"http://192.237.241.175:8090/snippets/"];
NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:url];
[urlRequest setHTTPMethod:#"GET"];
self.connTxtGet.text = self.recData ;
[urlRequest setValue:self.recData forHTTPHeaderField:#"Authorization"];
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);
}
}];
[dataTask resume];
}
You don't need to call these two method all together.
[self httpPostWithCustomDelegate];
[self sendHTTPGet];
You are making two request at the same time. But which response will come first you can not determine it. As you need data from "POST" request to make the "GET" request. Do something like this:
-(void) httpPostWithCustomDelegate{
.............
NSURLSessionDataTask * dataTask =[defaultSession dataTaskWithRequest:urlRequest
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
...................
...................
self.connTxtPost.text = [receivedData valueForKeyPath:#"access_token"];
self.recData = [receivedData valueForKeyPath:#"access_token"];
[self sendHTTPGet];
}
}];
[dataTask resume];
}
This will make sure when you make the "GET" request you have the "access_token". Hope this will work just fine. :)
Related
i am using APIs call in my iPhone (objective C) app. my APIS call returns Status code 200, but some time it does return 405 response. when i restart my app i do get proper response.
how to call back same API when i get other then 200 response or if i get error...so that i don't have to restart app again.
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
NSString *authValue = [NSString stringWithFormat:#"Bearer %#",
[arrTokenData valueForKey:#"Token"]];
//Configure session with common header fields
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfiguration.HTTPAdditionalHeaders = #{#"Authorization": authValue};
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
NSString *url = #"http://test.myserver.am/api/mobile/LookUps/getuserdata";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
if (!error) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if (httpResponse.statusCode == 200)
{
//Process the data
}
else if
{
// how to call back same API
}
}
else
{
// how to call back same API
}
}];
[task resume];
Thanks in advance
I considered as you created a generic method of network call. If you will get an error or other than 200 response. Just take the request details from your request and call that generic method with that request(URL).
Sample code:
NSURLSessionDataTask *DataTask = [session dataTaskWithRequest:theRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){
NSHTTPURLResponse *serverResponse = (NSHTTPURLResponse*)response;
if (error == nil) {
if (serverResponse.statusCode == 200) {
NSString *theXML = [[NSString alloc] initWithBytes:
[data bytes] length:[data length] encoding:NSUTF8StringEncoding];
NSLog(#"%#", theXML);
} else {
NSLog(#"%#, %#", serverResponse.URL, serverResponse.allHTTPHeaderFields);
//Call the generic network call method with the above details again
}
} else {
NSLog(#"%#", error. localizedDescription);
NSLog(#"%#, %#", serverResponse.URL, serverResponse.allHTTPHeaderFields);
//Call the generic network call method with the above details again
}
}];
[DataTask resume];
Create new thread and execute the failed requests.
Create one method and write your code in that method and call same method on error like below
- (void)callService {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
NSString *authValue = [NSString stringWithFormat:#"Bearer %#",
[arrTokenData valueForKey:#"Token"]];
//Configure session with common header fields
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfiguration.HTTPAdditionalHeaders = #{#"Authorization": authValue};
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
NSString *url = #"http://test.myserver.am/api/mobile/LookUps/getuserdata";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
if (!error) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if (httpResponse.statusCode == 200)
{
//Process the data
}
else
{
// how to call back same API
[self callService];
}
}
else
{
// how to call back same API
[self callService];
}
}];
[task resume];
}
I want to send image and param to server, image should in base64 format.
Ex : my url : http://.............
Parameters: image = image (base64 format), filename = my image name
I tried with NSURLSessions, image sent to server but image bytes is ZERO.
my code is:
UIImage *dataImage = [UIImage imageWithData:strImageBase64];
NSString *ImageBase64 = [UIImagePNGRepresentation(dataImage) base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
NSURL * url = [NSURL URLWithString:myurl];
NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:url];
NSString * params = [NSString stringWithFormat:#"image=%#&filename=%#",ImageBase64,#"unique2.png"];
[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);
}
}];
[dataTask resume];
I want to get data from different url in same thread. How can i do that.
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:defaultConfigObject];
for(int i=0;i<[url count];i++){
NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:url[i]];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:[param dataUsingEncoding:NSUTF8StringEncoding]];
NSURLSessionDataTask * dataTask =[session 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);
}
else{
// If no error occurs, check the HTTP status code.
NSInteger HTTPStatusCode = [(NSHTTPURLResponse *)response statusCode];
// If it's other than 200, then show it on the console.
if (HTTPStatusCode != 200) {
NSLog(#"HTTP status code = %d", HTTPStatusCode);
}
// Call the completion handler with the returned data on the main thread.
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
completionHandler(data);
}];
}
}];
[dataTask resume];
}
i want to get all value ..If i get that than i will save each url value in an array
I have a method that downloads a binary from a server and returns it.
But before the NSURLSession completes, my function is returning the value, so it's coming to be nil each time.
How can I wait till the download is complete and then return the binary?
Try this -
NSURLSession *delegateFreeSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
[[delegateFreeSession dataTaskWithURL: [NSURL URLWithString: #"http://www.example.com/"]
completionHandler:^(NSData *data, NSURLResponse *response,
NSError *error) {
NSLog(#"Got response %# with error %#.\n", response, error);
NSLog(#"DATA:\n%#\nEND DATA\n",
[[NSString alloc] initWithData: data
encoding: NSUTF8StringEncoding]);
[self loadDataToView:data]; // << your custom method inside the MyViewControllerClass
}] resume];
Your method should take a callback as an argument. Once the NSURLSession completion handler gets the object you need, you call that callback with the data (or an NSError object if you got an error back from the server)
You can't 'wait' for execution to continue after you get the data. By definition, such network operations are handled asynchronously, hence the need for a callback.
Update: sample code below
- (void)getFeed:(NSDictionary*)parameters fromURL:(NSString*)url withCallback:(void (^)(NSData *data, NSURLResponse *response, NSError *error))callback {
NSURL*newsfeedUrl = [NSURL URLWithString:url];
NSMutableURLRequest *newsfeedRequest = [NSMutableURLRequest requestWithURL:newsfeedUrl];
[newsfeedRequest addValue:#"XMLHTTPRequest" forHTTPHeaderField:#"X-Requested-With"];
newsfeedRequest.HTTPMethod = #"GET";
NSURLSessionDataTask *downloadNeewsfeedDataTask = [instance.session dataTaskWithRequest:newsfeedRequest completionHandler:^(NSData*data, NSURLResponse*response, NSError*error) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*) response;
NSLog(#"statusCode %ld", (long)httpResponse.statusCode);
//Do something here in your completion handler and call your callback function when ready (either with the data you expected, or with an error object. Alternatively, you can outright refrain from adding a completion handler block and simply put your callback argument as the completion handler (they must have the same signature).
callback(data, response, error);
}];
[downloadNeewsfeedDataTask resume];
}
Here is the example of completion handler for NSURLSession.
-(void) httpPostWithCustomDelegate{
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
NSURL * url = [NSURL URLWithString:#"http://hayageek.com/examples/jquery/ajax-post/ajax-post.php"];
NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:url];
NSString * params =#"name=Ravi&loc=India&age=31&submit=true";
[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);
}
}];
[dataTask resume];
}
Here is good tutorial for NSURLSession.
Since ASIHTTPRequest is deprecated, I am migrating my code to use NSURLSession based server communication. Currently, I am using NSDictionary "userInfo" property of ASIHTTPRequest to send additional user information. The description of "userInfo" in ASIHTTPRequest documentation is "Custom user information associated with the request (not sent to the server)".
After the request is processed, I re-fetch this "userInfo" object from the request object and take action accordingly.
My ASIHTTPRequest code example is
Request:
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:#"http://www.google.com"];
[request setDelegate:self];
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:1] forKey:#"requestCount"];
[request setUserInfo:userInfo];
I want to achieve same functionality through NSURLSession, how can I do this?
NSURLSession code example:
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: self.queue];
NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:url];
[urlRequest setTimeoutInterval:timeOutSeconds];
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);
}
}
}];
[dataTask resume];
Because you are using completion handler so you can use block variable, try below code:
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: self.queue];
NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:url];
[urlRequest setTimeoutInterval:timeOutSeconds];
__block NSDictionary *userInfo = [NSDictionary dictionaryWithObjectAndKeys...........];**
NSURLSessionDataTask * dataTask =[defaultSession dataTaskWithRequest:urlRequest
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(#"Response:%# %#\n", response, error);
NSLog(#"UserInfo: %#", userInfo);
if(error == nil)
{
NSString * text = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog(#"Data = %#",text);
}
}
}];
[dataTask resume];
The cleanest way to go is to subclass NSURLRequest and add the desired property - be it tag, or userInfo and use it the same way you are used to with ASIHTTP framework.