Multiple web service calls at the same time in iOS - ios

In my app i need to call two services at a time. for single service i am using the below code:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
// Instantiate a session object.
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
NSURL *url = [NSURL URLWithString:#"my link"];
// Create a data task object to perform the data downloading.
NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error != nil) {
// If any error occurs then just display its description on the console.
NSLog(#"%#", [error localizedDescription]);
}
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", (int)HTTPStatusCode);
} else {
NSMutableArray *jsonData = [NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingMutableContainers | NSJSONReadingMutableLeaves error:nil];
NSLog(#"json data ==========> %#", jsonData);
}
}
}];
// Resume the task.
[task resume];
by using this i am getting the data. Now, at the same time i need to call another service. How can i achieve this? and How i will get the data?

Related

iOS 9 : Get Value From NSURLSessionDataTask In Framework

I had iOS framework which it send JSON to server using NSURLSessionDataTask like this :
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
int responseStatusCode = [httpResponse statusCode];
if (responseStatusCode == 200)
{
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate onJsonHttpResult:data andStatusResponse:responseStatusCode];
});
}
else
{
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate onJsonHttpResult:nil andStatusResponse:responseStatusCode];
});
}
}];
[postDataTask resume];
but whenever I run it, [self.delegate onJsonHttpResult:nil andStatusResponse:responseStatusCode]; not called.
is there any way to get value outside NSURLSessionDataTask when it run inside the framework ?
Thanks
My suggestion is to create and use APIHelperClass with completionBlock.
That will be more easy and affective then use of custom Delegate as per my view.
To create it you can do as follow:
In APIHelperClass.h
#import <Foundation/Foundation.h>
#interface APIHelperClass : NSObject
+(void)apiCallSharedSessionPOST:(NSURLRequest *)request withCompletionHandlar:(void (^) (NSDictionary *dicResult,NSError *error, int status))completionBlock;
#end
And
APIHelperClass.m
#import "APIHelperClass.h"
#implementation APIHelperClass
+(void)apiCallSharedSessionPOST:(NSURLRequest *)request withCompletionHandlar:(void (^) (NSDictionary *dicResult,NSError *error, int status))completionBlock;
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error) {
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
int responseStatusCode = (int)[httpResponse statusCode];
if (error!=nil)
{
completionBlock(nil,error,responseStatusCode);
[task suspend];
}
else
{
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
completionBlock(dic,error,responseStatusCode);
[task suspend];
}
}];
[task resume];
}
Then you can use that class for whole App and you don't need to create custom Delegates always.
Then Use that where you want Like :
NSURLRequest *request;
/*
Configure your Request Here
*/
[APIHelperClass apiCallSharedSessionPOST:request withCompletionHandlar:^(NSDictionary *dicResult, NSError *error, int status) {
}];
Thanks for help but I still need delegate to return my value outside framework.
I got issued that whenever I done with NSURLSessionDataTask, delegate is became null, I think it cause that delegate already released after I got response from NSURLSessionDataTask, So I tried to change #property delegate to strong and it work. I can return my value using delegate again. Thanks

How to parse json data using singleton class

I have a singleton class where i have implemented a method to parse json data through URL. The code is as below
-(id)parseJsonDataWIthURL:(NSString *)url :(NSString*)datumm
{
NSMutableDictionary *arrrrr=[[NSMutableDictionary alloc]init];
NSMutableURLRequest *reqqq=[[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:url]];
NSData *dataaa=[datumm dataUsingEncoding:NSUTF8StringEncoding];
[reqqq setHTTPMethod:#"POST"];
[reqqq setHTTPBody:dataaa];
NSURLSessionConfiguration *configg=[NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession*sessionn=[NSURLSession sessionWithConfiguration:configg delegate:nil delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionDataTask *taskk=[sessionn dataTaskWithRequest:reqqq completionHandler:^(NSData *data,NSURLResponse *responce,NSError *error){
if(error)
{
NSLog(#"%#", [error localizedDescription]);
}else{
NSMutableDictionary *d = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments|NSJSONReadingMutableContainers error:&error];
NSLog(#"data %#",d);
[arrrrr setDictionary:d];
}
}];
[taskk resume];
return arrrrr;
}
The method returns no values, it is because the blocks takes time to execute within that method returns the result. So is there any way to wait until block completes and return the value.
ragul ml,
Simplest solution I can suggest is to use blocks :)
Here is how you can achieve it :) modify -(id)parseJsonDataWIthURL:(NSString *)url :(NSString*)datumm to,
-(void)parseJsonDataWIthURL:(NSString *)url :(NSString*)datumm withCompletionBlock:(void(^)(NSMutableArray *))completionBlock
{
NSMutableDictionary *arrrrr=[[NSMutableDictionary alloc]init];
NSMutableURLRequest *reqqq=[[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:url]];
NSData *dataaa=[datumm dataUsingEncoding:NSUTF8StringEncoding];
[reqqq setHTTPMethod:#"POST"];
[reqqq setHTTPBody:dataaa];
NSURLSessionConfiguration *configg=[NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession*sessionn=[NSURLSession sessionWithConfiguration:configg delegate:nil delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionDataTask *taskk=[sessionn dataTaskWithRequest:reqqq completionHandler:^(NSData *data,NSURLResponse *responce,NSError *error){
if(error)
{
NSLog(#"%#", [error localizedDescription]);
completionBlock(nil)
}else{
NSMutableDictionary *d = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments|NSJSONReadingMutableContainers error:&error];
NSLog(#"data %#",d);
[arrrrr setDictionary:d];
if (completionBlock) {
completionBlock(arrrrr);
}
}
}];
[taskk resume];
}
finally modify your call as,
[[YourSingletonClass sharedInstance] parseJsonDataWIthURL:your_url :datumm withCompletionBlock:^(NSMutableArray *array) {
if (array){
//web service is successful
}
}];

Google Place api URL iOS

I am creating an app that uses Google Place. Before I used to use Yahoo's api and had to use a url that was responsible for local search that was provided by yahoo. The url was following:
http://local.yahooapis.com/LocalSearchService/V3/localSearch?appid=SF0DVEvV34G4GnXEDU4SXniaDebJ_UvC1G1IuikVz3vpOJrBpyD.VqCJCVJHMh99He3iFz1Rzoqxb0b7Z.0-
Now since yahoo's api is discontinued I have decided to switch over to Google Place. But I cannot find an Url to use. I just dowlod the framework and use the api key. Where can I find such url for Google Place.
Register for the Google Places API by following the linke provided below:
https://code.google.com/apis/console
Refer Code Link for places Auto Search
https://github.com/AdamBCo/ABCGooglePlacesAutocomplete
NSString *const apiKey = #"*****23xAHRvnOf2BVG8o";
NSString * searchWord = #"search some place "
NSString *urlString = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/autocomplete/json?input=%#&types=establishment|geocode&radius=500&language=en&key=%#",searchWord,apiKey];
pragma mark - Network Methods
-(void)retrieveGooglePlaceInformation:(NSString *)searchWord withCompletion:(void (^)(BOOL isSuccess, NSError *error))completion {
if (!searchWord) {
return;
}
searchWord = searchWord.lowercaseString;
self.searchResults = [NSMutableArray array];
if ([self.searchResultsCache objectForKey:searchWord]) {
NSArray * pastResults = [self.searchResultsCache objectForKey:searchWord];
self.searchResults = [NSMutableArray arrayWithArray:pastResults];
completion(YES, nil);
} else {
NSString *urlString = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/autocomplete/json?input=%#&types=establishment|geocode&radius=500&language=en&key=%#",searchWord,apiKey];
NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *jSONresult = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
if (error || [jSONresult[#"status"] isEqualToString:#"NOT_FOUND"] || [jSONresult[#"status"] isEqualToString:#"REQUEST_DENIED"]){
if (!error){
NSDictionary *userInfo = #{#"error":jSONresult[#"status"]};
NSError *newError = [NSError errorWithDomain:#"API Error" code:666 userInfo:userInfo];
completion(NO, newError);
return;
}
completion(NO, error);
return;
} else {
NSArray *results = [jSONresult valueForKey:#"predictions"];
for (NSDictionary *jsonDictionary in results) {
}
//[self.searchResultsCache setObject:self.searchResults forKey:searchWord];
completion(YES, nil);
}
}];
[task resume];
}
}

command for JSON-Feed does not get executed in Objective-C

I am trying to fetch a JSON-feed but somehow the command is never executed. I have placed a NSLog just before the session gets called and that actually gets output on the console. The NSLog later "test" never gets output. I can't find out where the problem is. Another JSON request works just fine. Here is the code:
NSLog(#"fetchClassified started!");
// connect to webserver and ask for the feed
NSURL *url = [NSURL URLWithString:#"http://test.server/services/rest/v1/interface2?id=22"];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
// create a task that transfers the feed from the server
NSURLSessionTask *dataTask = [self.session dataTaskWithRequest:req
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data
options:0 error:nil];
NSLog(#"test %#", jsonObject);
self.classified = jsonObject[#"tasks"];
NSLog(#"%#", self.classified);
// put the output on the main queue (UI has to run always on main thread)
dispatch_async(dispatch_get_main_queue(), ^{
self.textView.text =self.classified;
});
}
];
[dataTask resume];
Thank you in advance for any hint on this!
JoeFryer solved it. self.session was nil.

Block not completing in iOS

I'm relatively new to iOS development but I'm working on an application to get a better understanding of development. I'm working with a web service and want to check the credentials a user enters. To do this I am making a simple get request with their credentials and then checking the http status for 200. Here is my code below:
-(BOOL)checkCredentials:(NSString *)username withPassword:(NSString *)password{
NSString *requestString = #"SOME URL";
NSURL *url = [NSURL URLWithString:requestString];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
NSData *userPasswordData = [[NSString stringWithFormat:#"%#:%#", username, password] dataUsingEncoding:NSUTF8StringEncoding];
NSString *base64EncodedCredential = [userPasswordData base64EncodedStringWithOptions:0];
NSString *authString = [NSString stringWithFormat:#"Basic %#", base64EncodedCredential];
NSURLSessionConfiguration *sessionConfig=[NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfig.HTTPAdditionalHeaders=#{#"Authorization":authString};
self.session=[NSURLSession sessionWithConfiguration:sessionConfig];
__block BOOL success = NO;
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if(!error){
NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response;
if (httpResp.statusCode == 200) {
success = YES;
}
}
NSMutableDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(#"%#", jsonObject);
dispatch_semaphore_signal(sema);
}];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
[dataTask resume];
return success;
}
I was going to use a semaphore to wait for the block to complete so I can check the status code and then return. But first it seems like my code just hangs, and I think that because I don't have a release, but that's not allowed with ARC. I'm not sure why it's hanging. Is there a better way to wait for the block to complete (without a semaphore) so I can return whether my credentials are valid?
Also is there a better way to pass the username and password so that it's not possible for someone to spoof the username and password?
Any help would be greatly appreciated.
Think simple!
Make your own completionHandler so that you won't deal with the return anymore, the caller will take the responsibility of result verification instead.
There's one thing you need to keep in mind, that if you want to modify anything related to UI (User Interface), you need to dispatch your completion block to main queue or you will get unexpected behavior, see more detail here.
Change your return type to void and add a completion block:
-(void)checkCredentials:(NSString *)username withPassword:(NSString *)password completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))myCompletion
{
NSString *requestString = #"http://google.com";
NSURL *url = [NSURL URLWithString:requestString];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// Here you return exactly what the NSURLSessionDataTask downloaded
// and pass it to the caller as an another completion block
myCompletion(data, response, error);
}];
[dataTask resume];
}
Caller's code, I assume that self is the caller:
[self checkCredentials:#"" withPassword:#"" completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if(!error){
// Result verification's here
NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response;
if (httpResp.statusCode == 200) {
NSLog(#"SUCESS");
}
}
}];
You code stops waiting for a semaphore and [dataTask resume] is never executed.
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); <=== waits here
[dataTask resume]; <=== never reached
I'd suggest not using the semaphore here. Do the work in your block instead.
As to username/password. If you worry about spoofing then SSL layer on top of HTTP is the answer.
This is a really dangerous pattern, because this call is going to block until the network request completes. If this is on the main thread, your app will stop responding and the watchdog may kill you.
That warning aside, the reason the block doesn't complete is because the network task is never started. You trap on your semaphore before you call resume, so your task never runs. I would also, personally use a dispatch_group to do the waiting.
To make it better, you would need to rewrite it asynchronously. Basically have your app continue to function, maybe disable the inputs, until the call completes, then run a block to re-enable them, or show an error:
// Assume your login button and whatever are exposed as properties here
self.loginButton.enabled = NO;
NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if(!error){
NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response;
if (httpResp.statusCode == 200) {
success = YES;
}
}
NSMutableDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(#"%#", jsonObject);
// Need to be back on the main queue, the call is complete
self.loginButton.enabled = YES;
}];
[dataTask resume];
Or, just to keep it the way you have it, but resolve the immediate issue, re-order your trap so that it happens after the task resumes:
[dataTask resume];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); // might want to time out here instead of waiting forever
return success;

Resources