synchronous NSURLSessionDataTask using objective-c - objective-c

I'm try to do synchronous NSURLSessionDataTask with the below code but unable to proceed.
__block NSData *rData = nil;
__block BOOL taskDone = NO;
__block NSData *rError = nil;
NSURL *url = [NSURL URLWithString:dataURL];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:1 timeoutInterval:30];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] delegate:nil delegateQueue:nil];
NSURLSessionDataTask *taskData = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
rData = [NSData dataWithData:data];
rError = [error copy];
taskDone = YES;
}];
[taskData resume];
while (taskDone == NO) {
if (_close == YES) {
[taskData cancel];
return nil;
}
usleep(20000);
}
I need to synchronous call so that I can remove the while loop which is not needed.
Below is my code with synchronous call using semaphore
dispatch_semaphore_t sem;
__block NSData *rData = nil;
__block BOOL taskDone = NO;
__block NSData *rError = nil;
NSURL *url = [NSURL URLWithString:dataURL];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:1 timeoutInterval:30];
// creating semaphore
    sem = dispatch_semaphore_create(0);
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] delegate:nil delegateQueue:nil];
NSURLSessionDataTask *taskData = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
rData = [NSData dataWithData:data];
rError = [error copy];
taskDone = YES;
//call semaphore
        dispatch_semaphore_signal(sem);
}];
[taskData resume];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
dispatch_release(sema);
// THIS part not sure... how can we accommodate this below code
while (taskDone == NO) {
if (_close == YES) {
[taskData cancel];
return nil;
}
usleep(20000);
}
above code could be correct ?

I understand that what you want to do is wait for the DataTask to be completed before continue with you code, the best way is to put your request in a function with a completionHandler.
First create a function that will return a NSURLSessionDataTask with a completion handler:
-(NSURLSessionDataTask*)startSessionDataTaskWithCompletionHandler:(void (^)(NSData *myData))completionBlock {
//Set your request
NSString *dataURL = #"www.yoururl.com";
NSURL *url = [NSURL URLWithString:dataURL];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:1 timeoutInterval:30];
// I recommend to use sharedSession because is a simple request, so its not needed a specific session configuration.
NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession] dataTaskWithRequest: request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (!error) {
if (completionBlock){
completionBlock(data);
return;
//When you call this function, the completionBlock will use this data
}
} else {
//Error handle
return;
}
}];
[dataTask resume];
return dataTask;
}
Then you can call this function from anywhere:
NSURLSessionTask *task = [self startSessionDataTaskWithCompletionHandler:^(NSData *myData) {
// put whatever code you want to perform when the asynchronous data task finish, for example:
rData = [NSData dataWithData:myData];
}];
if (!task) {
// handle failure to create task any way you want
}

You can make NSURLSessionDataTask synchronous with PromiseKit. Install it manually or add the following line to the Podfile if you use CocoaPods (tested with CocoaPods 1.7.3):
pod "PromiseKit", "6.10.0"
Add the following line to the top of the code file:
#import PromiseKit;
Then create a wrapper for your task:
- (AnyPromise*)promiseToLoadData:(NSString*)dataURL {
return [AnyPromise promiseWithResolverBlock:^(PMKResolver _Nonnull resolver) {
NSURL *url = [NSURL URLWithString:dataURL];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:1 timeoutInterval:30];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] delegate:nil delegateQueue:nil];
NSURLSessionDataTask *taskData = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error != nil) {
resolver([error copy]);
} else {
resolver([NSData dataWithData:data]);
}
}];
[taskData resume];
}];
}
Use wait to resolve the promise synchronously:
id value = [self promiseToLoadData:#"http://your.url"].wait;
if ([value isKindOfClass:[NSData class]]) {
NSLog(#"%#", [[NSString alloc] initWithData:value encoding:NSUTF8StringEncoding]);
}

Related

Getting error while fetching data from server using NSURLSession Datatask in objective c

I was trying to load data for the table using values from server.I am using NSURLSession datatask with completion handler. Whenever it reaches the nsurlsession, it shows error.This is the code which i used for getting data.
- (void)geturl:(NSString *)urlvalue datavalues:(NSString *)string fetchGreetingcompletion:(void (^)(NSDictionary *dictionary, NSError *error))completion{
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"%#%#?%#",common.getUrlPort,urlvalue,common.getappversion]];
NSLog(#"url=%#",url);
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:url];
[urlRequest addValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[urlRequest addValue:common.getauthtoken forHTTPHeaderField:#"Authorization"];
//Create POST Params and add it to HTTPBody
[urlRequest setHTTPMethod:#"GET"];
NSURLSessionDataTask * dataTask =[defaultSession dataTaskWithRequest:urlRequest
completionHandler:^(NSData *data, NSURLResponse *response, NSError *connectionError) {
NSLog(#"Response:%# %#\n", response, connectionError);
if (data.length > 0 && connectionError == nil)
{
NSDictionary *greeting = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
NSString *code = [NSString stringWithFormat:#"%#",[greeting valueForKey:#"code"]];
if([code isEqualToString:#"-1"]){
[self loaderrorview:greeting];
}
else{
if (completion)
completion(greeting, connectionError);
}
}
else if(data == nil){
NSDictionary *errorDict=[[NSDictionary alloc]initWithObjectsAndKeys:#"Server Connection Failed",#"error", nil];
if (completion)
completion(errorDict,connectionError);
}
else
{
NSDictionary *greeting = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
if (completion)
completion(greeting, connectionError);
}
}];
[dataTask resume];
}
The code which i used for getting data from server:
-(void)getdataexplore{
if (!common.checkIfInternetIsAvailable) {
[self.view makeToast:Nointernetconnection];
} else {
NSLog(#"There is internet connection");
[SVProgressHUD setDefaultMaskType:SVProgressHUDMaskTypeBlack];
[SVProgressHUD showWithStatus:#"Loading..."];
[apiservice geturl:loadexploredata datavalues:nil fetchGreetingcompletion:^(NSDictionary *dictionary, NSError *error) {
//NSLog(#"Test %# Error %#",dictionary,error);
if(error == nil){
authDictionary = dictionary;
[self loaddata];
}
else{
[SVProgressHUD dismiss];
[view_business makeToast:#"Request timed out" duration:2.0 position:CSToastPositionCenter];
}
}];
}
}
The code which i used for storing server data to array:
-(void)loaddata
{
[SVProgressHUD setDefaultMaskType:SVProgressHUDMaskTypeBlack];
[SVProgressHUD showWithStatus:#"Loading..."];
//[SVProgressHUD dismiss];
NSString *msg = [authDictionary valueForKey:#"msg"];
NSString *code = [NSString stringWithFormat:#"%#",[authDictionary valueForKey:#"code"]];
if([code isEqualToString:#"201"]){
NSDictionary *explore = [authDictionary valueForKey:#"explore_obj"];
arr_CBcategories = [explore valueForKey:#"cb_categories"];
[common setarrCBCaterory:arr_CBcategories];
arr_CBcategoryid = [arr_CBcategories valueForKey:#"id"];
[common setarrCateroryID:arr_CBcategoryid];
arr_CBcategorytitle = [arr_CBcategories valueForKey:#"title"];
[common setarrCaterorytitle:arr_CBcategorytitle];
arr_CBcategoryslug = [arr_CBcategories valueForKey:#"slug"];
[common setarrCateroryslug:arr_CBcategoryslug];
arr_CBcategoryimage = [arr_CBcategories valueForKey:#"image"];
[common setarrCateroryimage:arr_CBcategoryimage];
arr_CBcategorycode = [arr_CBcategories valueForKey:#"code"];
}
I am getting error like "Unable to run main thread". Any solution for this.

Objective C - HTTP GET Request API

I've been trying to query Tesco's API Service. Although I've managed comfortably on Python with this, I have been having some trouble with making a request using Objective C. Nothing is being logged on the output. Any help would be appreciated. The program code is shown below:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
#autoreleasepool {
NSURLSessionConfiguration *defaultSessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration:defaultSessionConfiguration];
NSURL *url = [NSURL URLWithString:#"https://dev.tescolabs.com/product/?gtin=4548736003446"];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
NSString *postParams = #"subscription key=93a6e21eed2e4ca3a858a0f1fc5aaf03";
NSData *postData = [postParams dataUsingEncoding:NSUTF8StringEncoding];
[urlRequest setHTTPMethod:#"GET"];
[urlRequest setHTTPBody:postData];
NSURLSessionDataTask *dataTask = [defaultSession dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(#"Response: %#",response);
NSLog(#"Data: %#",data);
NSLog(#"Error: %#",error);
}];
[dataTask resume];
}
return 0;
}
I had no choice but to present an answer ... Notice the runloop code:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSURLSessionConfiguration *defaultSessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration:defaultSessionConfiguration];
NSURL *url = [NSURL URLWithString:#"https://dev.tescolabs.com/product/?gtin=4548736003446"];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
NSString *postParams = #"subscription key=93a6e21eed2e4ca3a858a0f1fc5aaf03";
NSData *postData = [postParams dataUsingEncoding:NSUTF8StringEncoding];
[urlRequest setHTTPMethod:#"GET"];
[urlRequest setHTTPBody:postData];
__block BOOL done = NO;
NSURLSessionDataTask *dataTask = [defaultSession dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(#"Response: %#",response);
NSLog(#"Data: %#",data);
NSLog(#"Error: %#",error);
done = YES;
}];
[dataTask resume];
while (!done) {
NSDate *date = [[NSDate alloc] initWithTimeIntervalSinceNow:0.1];
[[NSRunLoop currentRunLoop] runUntilDate:date];
}
}
return 0;
}
Basically you need a run loop to perform a background task.
Your request does not work because the body POST data are not considered using a GET request.
All parameters must be passed in the URL.
To implement the run loop just use CFRunLoopRun() and CFRunLoopStop().
Do not use NSRunLoop ... runUntilDate with a while loop
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
#autoreleasepool {
NSURLSessionConfiguration *defaultSessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration:defaultSessionConfiguration];
NSURL *url = [NSURL URLWithString:#"https://dev.tescolabs.com/product/? ... "];
NSURLSessionDataTask *dataTask = [defaultSession dataTaskWithURL: url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(#"Response: %#",response);
NSLog(#"Data: %#",data);
NSLog(#"Error: %#",error);
CFRunLoopStop(CFRunLoopGetCurrent());
exit(EXIT_SUCCESS);
}];
[dataTask resume];
}
CFRunLoopRun();
return 0;
}
-dataTaskWithRequest:completionHandler: is asynchronous. You are queuing up an action which would be completed later then exiting the program before it completes.
You need a mechanism to wait for the data task to complete before exiting the program.
See: https://stackoverflow.com/a/34200617/1298400 for an example waiting mechanism.
Try this u need to pass subscription key in header in this request
NSDictionary *headers = #{ #"ocp-apim-subscription-key": #"YourKey"};
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"YourURL"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
[request setHTTPMethod:#"GET"];
[request setAllHTTPHeaderFields:headers];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(#"%#", error);
} else {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
NSLog(#"%#", httpResponse);
}
}];
[dataTask resume];
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
#autoreleasepool {
NSURLSessionConfiguration *defaultSessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration:defaultSessionConfiguration];
NSURL *url = [NSURL URLWithString:#"https://dev.tescolabs.com/product/? ... "];
NSURLSessionDataTask *dataTask = [defaultSession dataTaskWithURL: url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(#"Response: %#",response);
NSLog(#"Data: %#",data);
NSLog(#"Error: %#",error);
CFRunLoopStop(CFRunLoopGetCurrent());
exit(EXIT_SUCCESS);
}];
[dataTask resume];
}
CFRunLoopRun();
return 0;
}

NSMutableURLRequest sending 2 times while using NSURLSession

I am using NSMutableURLRequest is working correct when I am using
- (void)postAsynchronousOnQueue:(NSOperationQueue*)queue completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))completionHandler {
NSURLRequest* request = [self createPostRequest];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:completionHandler];
}
-(NSURLRequest*)createPostRequest {
NSMutableURLRequest* request = [[HttpRequest requestWithRelativePath:#"/photo"] toNSMutableURLRequest];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[self encodeParamsForUpload]];
return request;
}
But the issue is when my app is in background mode it won't work.
Here is my HttpRequest class method:
+(id)requestWithRelativePath:(NSString*)docpath {
return [[HttpRequest alloc] initWithRelativePath:docpath server:server username:email password:password];
}
-(id)initWithRelativePath:(NSString*)docpath server:(NSString*)server username:(NSString*)username password:(NSString*)password {
if (self = [super init]) {
docpath = [docpath stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
_request = [self createRequestWithDocPath:docpath server:server username:username password:password];
}
return self;
}
- (NSMutableURLRequest*)createRequestWithDocPath:(NSString*)docpath server:(NSString*)server username:(NSString*)username password:(NSString*)password {
NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:#"https://%#%#", server, docpath]];
NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setTimeoutInterval:120.0];
if ((username != nil) && (password != nil)){
NSString *authStr = [NSString stringWithFormat:#"%#:%#", username, password];
NSData *authData = [authStr dataUsingEncoding:NSUTF8StringEncoding];
NSString *authValue = [NSString stringWithFormat:#"Basic %#", [self base64Encoding:authData]];
[request setValue:authValue forHTTPHeaderField:#"Authorization"];
}
return request;
}
From, stack overflow I found NSURLSession to work API calls in background. So I used NSURLSession. Here is my updated code which I did:
- (void)postAsynchronousOnQueue:(NSOperationQueue*)queue completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))completionHandler {
NSURLRequest* request = [self createPostRequest];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:completionHandler];
}
-(NSURLRequest*)createPostRequest {
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration ephemeralSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
NSMutableURLRequest* request = [[HttpRequest requestWithRelativePath:#"/photo"] toNSMutableURLRequest];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[self encodeParamsForUpload]];
//Create task
NSURLSessionDataTask *dataTask = [defaultSession dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
//Handle your response here
[[NSURLSession sharedSession]invalidateAndCancel];
}];
[dataTask resume];
return request;
}
But, when I am using NSURLSession the request is sending two times I already put the breakpoints in NSMutableURLRequestline but it call only once.
Please, help me to solve the issue.
Your createPostRequest is creating a request and submitting it via NSURLSession. But it also returns the NSURLRequest and postAsynchronousOnQueue proceeds to submit it again, this time through the deprecated NSURLConnection.
Remove the NSURLConnection code and just rely upon NSURLSession to issue the request.
For example:
- (void)postAsynchronousOnQueue:(NSOperationQueue*)queue completionHandler:(void (^)(NSData *, NSURLResponse*, NSError*))completionHandler {
NSURLSession *defaultSession = [NSURLSession sharedSession];
NSMutableURLRequest* request = [[HttpRequest requestWithRelativePath:#"/photo"] toNSMutableURLRequest];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[self encodeParamsForUpload]];
NSURLSessionDataTask *dataTask = [defaultSession dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
//Handle your response here
[queue addOperationWithBlock:^{
completionHandler(data, response, error);
}];
}];
[dataTask resume];
}

Objective C Block within Block generates Leak. How can I solve it?

Why does this code generates a leak? How could it be solved?
This is the original call:
NSString * url = #"https://theserverurl/user/login" ;
NSDictionary *parameters = #{#"login":#"the-email#mail.com", #"password":#"encrypted-password"} ;
[[BackEndAPI sharedManager] NSURLSessionOperation: #"POST" url: url parameters: parameters success:^(NSURLRequest *request, NSHTTPURLResponse * response, id responseObject) {
// Success
} failure:^(IDLEngineError *engineError) {
// Failure
}] ;
This is the singleton which handles the NSURL request:
- (NSMutableURLRequest *) NSURLSessionOperation:(NSString *) restOperation
url:(NSString *)url
parameters:(id)parameters
success:(void (^)(NSMutableURLRequest *request, NSHTTPURLResponse * response, id responseObject))success
failure:(void (^)(IDLEngineError *))failure {
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
__weak id weakSelf = self ;
// POST
if ([restOperation isEqualToString:#"POST"]) {
NSError *error;
NSURLSession *session = [NSURLSession sessionWithConfiguration: sessionConfig ];
// Create the request
__block NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: url ] ];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"] ;
request.HTTPMethod = #"POST";
NSData *postData = [NSJSONSerialization dataWithJSONObject: parameters options: 0 error:&error];
[request setHTTPBody:postData];
// Perform operation
NSURLSessionDataTask * task = [session dataTaskWithRequest: request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// This generates a leak!!!!
success(request, nil, nil) ;
}] ;
[task resume] ;
}
return nil ;
}
Please take a look to the leaked app on GitHub:
https://github.com/arkyxperience/myleakedapp
Find also here the report (screenshot) coming from Instruments:
It turns out the leak is with NSURLSessionDataTask. If you isolate the following piece of code, the leak will remain:
NSString * url = #"https://theserverurl/user/login" ;
NSDictionary *parameters = #{#"login":#"the-email#mail.com", #"password":#"encrypted-password"} ;
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
NSError *error;
NSURLSession *session = [NSURLSession sessionWithConfiguration: sessionConfig ];
// Create the request
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: url ] ];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"] ;
request.HTTPMethod = #"POST";
NSData *postData = [NSJSONSerialization dataWithJSONObject: parameters options: 0 error:&error];
[request setHTTPBody:postData];
// Perform operation
NSURLSessionDataTask * task = [session dataTaskWithRequest: request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
}] ;
[task resume] ;
Am I doing anything wrong?
OK, i tried your github code, looks like there is no leak. What object is leaking after all? To test this code please add restoration id to your controller. In this code dealloc is being triggered even tho i don't use weak to call controller. So controller is not leaking, complete block does not have a retain loop. Don't see anything that can leak in NSURLSessionOperation:. So what exactly is leaking?
- (void)viewDidLoad {
[super viewDidLoad];
NSString * url = #"https://google.com" ;
NSDictionary *parameters = #{#"login":#"the-email#mail.com", #"password":#"encrypted-password"} ;
[[BackEndAPI sharedManager] NSURLSessionOperation: #"POST" url: url parameters: parameters success:^(NSURLRequest *request, NSHTTPURLResponse * response, id responseObject) {
NSLog(#"finish");
dispatch_async(dispatch_get_main_queue(), ^{
self.view.window.rootViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"ViewController"];
});
} failure:^(NSError * error) {
NSLog(#"fail");
}];
}
- (void)dealloc {
NSLog(#"Did dealloc");
}

Simple objective-c GET request

Most of the information here refers to the abandoned ASIHTTPREQUEST project so forgive me for asking again.
Effectively, I need to swipe a magnetic strip and send the track 2 data to a webservice that returns "enrolled" or "notenrolled" (depending on the status of the card...)
So my data comes in simply as
NSData *data = [notification object];
And then I need to pass this to a url to the order of
http://example.com/CardSwipe.cfc?method=isenrolled&track2=data
And then just receive a response string...
I've searched a ton and there seems to be some conflicting answers as to whether this should be accomplished simply with AFNetworking, RESTkit, or with the native NSURL/NSMutableURLRequest protocols.
The options for performing HTTP requests in Objective-C can be a little intimidating. One solution that has worked well for me is to use NSMutableURLRequest. An example (using ARC, so YMMV) is:
- (NSString *) getDataFrom:(NSString *)url{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setHTTPMethod:#"GET"];
[request setURL:[NSURL URLWithString:url]];
NSError *error = nil;
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];
}
Update:
Your question's title, and tagging say POST, but your example URL would indicate a GET request. In the case of a GET request, the above example is sufficient. For a POST, you'd change it up as follows:
- (NSString *) getDataFrom:(NSString *)url withBody:(NSData *)body{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:body];
[request setValue:[NSString stringWithFormat:#"%d", [body length]] forHTTPHeaderField:#"Content-Length"];
[request setURL:[NSURL URLWithString:url]];
/* the same as above from here out */
}
Update for iOS 9:
So, [NSURLConnection sendSynchronousRequest] is deprecated starting from iOS 9. Here's how to do a GET request using NSURLSession starting from iOS 9
GET Request
// making a GET request to /init
NSString *targetUrl = [NSString stringWithFormat:#"%#/init", baseUrl];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setHTTPMethod:#"GET"];
[request setURL:[NSURL URLWithString:targetUrl]];
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:
^(NSData * _Nullable data,
NSURLResponse * _Nullable response,
NSError * _Nullable error) {
NSString *myString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Data received: %#", myString);
}] resume];
POST Request
// making a POST request to /init
NSString *targetUrl = [NSString stringWithFormat:#"%#/init", baseUrl];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
//Make an NSDictionary that would be converted to an NSData object sent over as JSON with the request body
NSDictionary *tmp = [[NSDictionary alloc] initWithObjectsAndKeys:
#"basic_attribution", #"scenario_type",
nil];
NSError *error;
NSData *postData = [NSJSONSerialization dataWithJSONObject:tmp options:0 error:&error];
[request setHTTPBody:postData];
[request setHTTPMethod:#"POST"];
[request setURL:[NSURL URLWithString:targetUrl]];
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:
^(NSData * _Nullable data,
NSURLResponse * _Nullable response,
NSError * _Nullable error) {
NSString *responseStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Data received: %#", responseStr);
}] resume];
Tested 100% working
Only for Objective C
-(void)fetchData
{
NSURLSessionConfiguration *defaultSessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration:defaultSessionConfiguration];
// Setup the request with URL
NSURL *url = [NSURL URLWithString:#"https://test.orgorg.net/ios/getStory.php?"];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
// Convert POST string parameters to data using UTF8 Encoding
NSString *postParams = #"";
NSData *postData = [postParams dataUsingEncoding:NSUTF8StringEncoding];
// Convert POST string parameters to data using UTF8 Encoding
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:postData];
// Create dataTask
NSURLSessionDataTask *dataTask = [defaultSession dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *results = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
//JSON Parsing....
NSString *message = results[#"Message"];
BOOL status = results[#"Status"];
if (status){
// Here you go for data....
}else{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:#"App"
message:message
preferredStyle:UIAlertControllerStyleAlert]; // 1
UIAlertAction *firstAction = [UIAlertAction actionWithTitle:#"Ok"
style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
NSLog(#"You pressed button one");
}]; // 2
[alert addAction:firstAction]; // 4
[self presentViewController:alert animated:YES completion:nil];
}
}];
// Fire the request
[dataTask resume];
}
For Objective c :
-(void)loadData:(NSString*)url{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"https://jsonplaceholder.typicode.com/posts"]];
[request setHTTPMethod:#"GET"];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
[[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSMutableArray *jsonArray = (NSMutableArray *)[NSJSONSerialization JSONObjectWithData:data options:NSASCIIStringEncoding error:&error];
if([self.delegate respondsToSelector:#selector(loadingData:)]){
[self.delegate loadingData:jsonArray];
}
}] resume];
}
Swift 5.5:
// MARK: - Posts
func getPosts(endPath : String, completion: #escaping ([Post]) -> ()) {
let urlPath = Constants.Network.BASE_URL + endPath
guard let url = URL(string: urlPath) else {
print("Invalid URL")
return
}
var request = URLRequest(url: url)
request.httpMethod = Constants.Network.HTTPS_METHOD
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
if let decodedResponse = try? JSONDecoder().decode([Post].self, from: data) {
DispatchQueue.main.async {
completion(decodedResponse)
}
return
}
}
print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
}.resume()
}
**Simply Call and get your JSON Data.**
-(void)getJSONData
{
NSURL *url = [NSURL URLWithString:#"http://itunes.apple.com/us/rss/topaudiobooks/limit=10/json"];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *data = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSError *erro = nil;
if (data!=nil) {
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&erro ];
if (json.count > 0) {
for(int i = 0; i<10 ; i++){
[arr addObject:[[[json[#"feed"][#"entry"] objectAtIndex:i]valueForKeyPath:#"im:image"] objectAtIndex:0][#"label"]];
}
}
}
dispatch_sync(dispatch_get_main_queue(),^{
[table reloadData];
});
}];
[data resume];
}