I have a section of code that is producing pour performance and not working as expected. it utilizes the SVProgressHUD from the following github repository at https://github.com/samvermette/SVProgressHUD. I have an area of code where I need to use [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]. I want to have a progress hud displayed before the synchronous request and then dismissed after the request has finished. Here is the code in question:
//Display the progress HUB
[SVProgressHUD showWithStatus:#"Signing Up..." maskType:SVProgressHUDMaskTypeClear];
NSError* error;
NSURLResponse *response = nil;
[self setUserCredentials];
// create json object for a users session
NSDictionary* session = [NSDictionary dictionaryWithObjectsAndKeys:
firstName, #"first_name",
lastName, #"last_name",
email, #"email",
password, #"password",
nil];
NSData *jsonSession = [NSJSONSerialization dataWithJSONObject:session options:NSJSONWritingPrettyPrinted error:&error];
NSString *url = [NSString stringWithFormat:#"%#api/v1/users.json", CoffeeURL];
NSURL *URL = [NSURL URLWithString:url];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:30.0];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:[NSString stringWithFormat:#"%d", [jsonSession length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:jsonSession];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSDictionary *JSONResponse = [NSJSONSerialization JSONObjectWithData:[dataString dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:&error];
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
NSInteger statusCode = httpResponse.statusCode;
NSLog(#"Status: %d", statusCode);
if (JSONResponse != nil && statusCode == 200)
{
//Dismiss progress HUB here
[SVProgressHUD dismiss];
return YES;
}
else
{
[SVProgressHUD dismiss];
return NO;
}
For some reason the synchronous request blocks the HUB from being displayed. It displays immediately after the synchronous request happens, unfortunatly this is also when it is dismissed. The behaviour displayed to the user is that the app hangs, waits for the synchronous request to finish, quickly flashes the HUB and then becomes responsive again. How can I fix this issue? I want the SVProgressHUB to be displayed during this hang time, how can I do this?
You could try performing hte request like this and handle the rest from inside a block. The code inside the block will only when run when the request has returned.
So it could be something like this:
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSDictionary *JSONResponse = [NSJSONSerialization JSONObjectWithData:[dataString dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:&error];
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
NSInteger statusCode = httpResponse.statusCode;
NSLog(#"Status: %d", statusCode);
if (JSONResponse != nil && statusCode == 200)
{
//Dismiss progress HUB here
[SVProgressHUD dismiss];
}
else
{
[SVProgressHUD dismiss];
}
}];
Yes and this make complete sense, since the HUD is being displayed in the main thread, all UI animation are.
Then you start the the request which is blocking the main thread.
You must either do the the request in the background, which makes sense for all network requests or delay the blocking call to give your UI time to update.
I really suggest that you use the asynchronous request, because this will give you app a more responsive nature even if you app needs to wait for a request to finish before doing anything else.
Related
//Below is the code i have used to perform simple httpPOST. But app hangs on App launch on splash screen and crashes . i am doing an API Call on applaunch in Appdelegate
- (NSDictionary *)postUserRegWithUrl:(NSString *)urlString andParams:(NSString *)paramString{
NSString * encodedString = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(
NULL,
(CFStringRef)paramString,
NULL,
(CFStringRef)#"+",
kCFStringEncodingUTF8 ));
NSDictionary *responseDictionary;
NSError *err;
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#%#",kBaseProdURL,urlString]]];
NSData *data = [encodedString dataUsingEncoding:NSUTF8StringEncoding];
[request setTimeoutInterval:60.0];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:data];
NSLog(#"the data Details is =%#", request);
NSURLResponse *response;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];
NSString *resSrt = [[NSString alloc]initWithData:responseData encoding:NSASCIIStringEncoding];
NSLog(#"got response==%#", resSrt);
if(resSrt.length)
{
responseDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&err];
NSLog(#"Response dictionary formed is =%#", responseDictionary);
} else {
NSLog(#"failed to connect");
[self showAlertViewTitle:#"Please try later" withMessage:#"Something went wrong"];
}
return responseDictionary;
}
You shouldn't execute your network calls synchronously, especially on main thread. Either use sendAsynchronousRequest or just use any good networking library, like AFNetworking, which do this out of the box.
First set the timeoutInterval for your request. if your request takes more time then you have to stop the api call and inform the user with proper error message.
For example:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:1200.0];
Don't use Synchronised Request. It will block your main thread.
If your network is slow or server is not responding then your app will take more time to load. Which is not good for the user experience.
Remember, your app’s load time is your first chance to impress your users.
Use Asynchronised Request of the NSURLConnection. Handle the response in the api completion block.
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
NSString *resSrt = [[NSString alloc]initWithData:data encoding:NSASCIIStringEncoding];
NSLog(#"got response==%#", resSrt);
if(resSrt.length)
{
responseDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&err];
NSLog(#"Response dictionary formed is =%#", responseDictionary);
} else {
NSLog(#"failed to connect");
}
}];
Change queue:[NSOperationQueue mainQueue] parameter based on your need.
queue -> An NSOperationQueue upon which the handler block will
be dispatched.
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) {
}];
}
}];
I am new in iOS application development. I have one problem in login page.
Sometimes it will take long time for log in. I am using this code to send or receive a request from a httpserver.
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonData1
options:0 // Pass 0 if you don't care about the readability of the generated string
error:&error];
if (!jsonData) {
NSLog(#"Got an error: %#", error);
} else {
jsonString= [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(#"converted json string is %#",jsonString);
}
NSData *postData = [[[NSString alloc] initWithFormat:#"method=methodName&email=%#&password=%#", user_name, pass_word] dataUsingEncoding:NSASCIIStringEncoding ];
NSString *postLength = [NSString stringWithFormat:#"%ld",[postData length]];
jsonData=[jsonString dataUsingEncoding:NSASCIIStringEncoding];
NSLog(#"the final passing json data is %#",jsonData);
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"http:urladdress"]];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"\"Accept\""];
[request setValue:#"application/json" forHTTPHeaderField:#"\"Content-Type\""];
[request setValue:postLength forHTTPHeaderField:#"\"Content-Length\""];
[request setValue:#"application/x-www-form-urlencoded;" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:jsonData];
NSError *requestError = [[NSError alloc] init];
NSHTTPURLResponse *response = nil;
NSData *urlData = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&requestError];
//if communication was successful
if ([response statusCode] >= 200 && [response statusCode] < 300) {
NSError *serializeError = nil;
NSString* newStr = [NSString stringWithString :[urlData bytes]];
NSDictionary *jsonData = [NSJSONSerialization
JSONObjectWithData:urlData
options:NSJSONReadingAllowFragments
error:&serializeError];
NSLog(#"recdata %#",jsonData);
}
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (connection)
{
NSLog(#"theConnection is succesful");
self.receivedData = [NSMutableData data];
}
[connection start];
[self readFromDataBase];
if (dataCheck==true) {
[self checkPassword];
}
is there any way to login faster.?
Maybe the connection is slow because your server or your connection quality.
Did you try with async? It won't freeze your app when waiting the respond
Asynchronous NSURLConnection Scheme Tutorial
For your program, replace the sendSync method:
NSData *urlData = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&requestError];
by sendAsync method:
NSOperationQueue *mainQueue = [[NSOperationQueue alloc] init];
[mainQueue setMaxConcurrentOperationCount:5];
[NSURLConnection sendAsynchronousRequest:request queue:mainQueue completionHandler:^(NSURLResponse *response, NSData *urlData, NSError *requestError) {
// doing somethings ...
// if communication was successful ...
}];
I am creating an asynchronous NSURLconnection in a popup view in ios.
To implement the asynchronous NSURLconnection I implement the methods of the NSURLDelegate.
The problem occurs when the user taps outside the popup view and the view is dismissed.
leaving the nsurlconnection callbacks and other actions inside the view incomplete.
How can I assure that the actions inside the popup complete inspite of the dismissal of the view?
I tried putting an activity indicator inside the popup view till the actions are completed, but even then a tap outside the popup view dismisses the view.
I dont want the user to be left with an inactive app till actions are completed, instead I want the actions to be completed in the background.
If you want to send an asynchronous connection you can use this methods.
GET REQUEST
-(void)placeGetRequest:(NSString *)action withHandler:(void (^)(NSURLResponse *response, NSData *data, NSError *error))ourBlock {
NSString *url = [NSString stringWithFormat:#"%#/%#", URL_API, action];
NSURL *urlUsers = [NSURL URLWithString:url];
NSURLRequest *request = [NSURLRequest requestWithURL:urlUsers];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:ourBlock];
}
POST REQUEST
-(void)placePostRequest:(NSString *)action withData:(NSDictionary *)dataToSend withHandler:(void (^)(NSURLResponse *response, NSData *data, NSError *error))ourBlock {
NSString *urlString = [NSString stringWithFormat:#"%#/%#", URL_API, action];
NSLog(urlString);
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// Creamos el JSON desde el data
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dataToSend options:0 error:&error];
NSString *jsonString;
if (! jsonData) {
NSLog(#"Got an error: %#", error);
} else {
jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSData *requestData = [NSData dataWithBytes:[jsonString UTF8String] length:[jsonString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:[NSString stringWithFormat:#"%d", [requestData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody: requestData];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:ourBlock];
}
}
EXAMPLE OF USE
- (void) getMyMethod:(NSString *)myParam1
myParam2:(NSString *)myParam2
myParam3:(NSString *)myParam3
calledBy:(id)calledBy
withSuccess:(SEL)successCallback
andFailure:(SEL)failureCallback{
[self placeGetRequest:[NSString stringWithFormat:#"api/myMethod?myParam1=%#&myParam2=%#&myParam3=%#",myParam1, myParam2, myParam3]
withHandler:^(NSURLResponse *response, NSData *rawData, NSError *error) {
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
NSInteger code = [httpResponse statusCode];
NSLog(#"%ld", (long)code);
if (code == 0){
// error
} else if (!(code >= 200 && code < 300) && !(code == 500)) {
NSString *string = [[NSString alloc] initWithData:rawData
encoding:NSUTF8StringEncoding];
NSLog(#"ERROR (%ld): %#", (long)code, string);
[calledBy performSelector:failureCallback withObject:string];
} else {
// If you receive a JSON
NSMutableDictionary *result = [NSJSONSerialization JSONObjectWithData:rawData options:0 error:nil];
// If you receive an Array
// NSArray *result = [NSJSONSerialization JSONObjectWithData:rawData options:0 error:nil];
// If you receive a string
// NSString *result = [[NSString alloc] initWithData:rawData encoding:NSUTF8StringEncoding];
[calledBy performSelector:successCallback withObject:result];
}
}];
}
CALL YOU MUST DO IN YOUR VIEW/CONTROLLER/ETC
(...)
[api getMyMethod:myParam1Value myParam2:myParam2Value myParam3:myParam3Value calledBy:self withSuccess:#selector(getMyMethodDidEnd:) andFailure:#selector(getMyMethodFailureFailure:)];
(...)
// Don't forget to set your callbacks functions or callbacks will do your app crash
-(void)getMyMethodDidEnd:(id)result{
// your actions with the result
// ...
}
-(void)getMyMethodFailure:(id)result{
// your actions with the result
// ...
}
To prevent the dismissal of popup view when tapping out side u need to implement this delegate method
- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController
{
return NO;
}
dismiss it by using the action
- (void)someAction
{
//check the operations are completed
.....
.....
[popoverController dismissPopoverAnimated:YES];
}
Undoubtedly, people will shake their head in shame at the following, but I would appreciate the help.
I seem to make the same calls to NSURLSessionUploadTask with pretty much the same structure throughout the program. Hence, I am trying to make it a method which I can call from anywhere in the program and, when it's complete, return the NSDictionary to the call which made it.
Currently I have the following:
-(NSDictionary *)serverRequest:(NSString *)requestURL withDictionary:(NSDictionary *)sendDict {
NSURL *homeURL = [[NSURL alloc] initWithString:[NSString stringWithFormat:#"%#/%#",baseURL, requestURL]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:homeURL];
[request setHTTPMethod:#"POST"];
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request addValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setCachePolicy:NSURLCacheStorageAllowedInMemoryOnly];
NSData *sentData = [NSJSONSerialization dataWithJSONObject:sendDict options:0 error:nil];
NSURLSessionUploadTask *uploadTask = [_session uploadTaskWithRequest:request fromData:sentData completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
returnedData = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
if ([returnedData[#"code"] isEqualToString:#"OK"])
{
dispatch_async(dispatch_get_main_queue(), ^{
return returnedData;
});
}
}];
[uploadTask resume];
}
So I pass in the URL I want to call, and the NSDictionary which is then sent to the server. The server replies, with a JSON response, which I then turn into returnedData. I simply wish to pass this data back to the call which made it ... something like:
NSDictionary *mydata = #{#"email": userRegisterTextFieldEmailAddress.text};
NSDictionary *passedBackData = [self serverRequest:#"checkUserName" withDictionary:mydata];
When I try this it won't build as the dispatch_async isn't the right format etc, etc. I have tried to read up on this, and can't believe it's a hard problem? Surely others aren't making the same call with the same code each time they want to return some data from a web server?
Thanks in advance for any help you can give in clearing up my misunderstanding.
What you'd generally do is add a completion block parameter to your method, that specifies what you want to do upon receiving the response. So, add a block parameter to your method and add the code that calls that block, something like:
- (void) serverRequest:(NSString *)requestURL withDictionary:(NSDictionary *)sendDict completion:(void (^)(id responseObject, NSError *error))completion
{
NSURL *homeURL = [[NSURL alloc] initWithString:[NSString stringWithFormat:#"%#/%#", baseURL, requestURL]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:homeURL];
[request setHTTPMethod:#"POST"];
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request addValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setCachePolicy:NSURLCacheStorageAllowedInMemoryOnly];
NSData *sentData = [NSJSONSerialization dataWithJSONObject:sendDict options:0 error:nil];
NSURLSessionUploadTask *uploadTask = [_session uploadTaskWithRequest:request fromData:sentData completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// report any network-related errors
if (!data) {
if (completion) {
dispatch_async(dispatch_get_main_queue(), ^{
completion(nil, error);
});
}
return;
}
// report any errors parsing the JSON
NSError *parseError = nil;
returnedData = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
if (!returnedData) {
if (completion) {
dispatch_async(dispatch_get_main_queue(), ^{
completion(nil, parseError);
});
}
return;
}
// if everything is ok, then just return the JSON object
if (completion) {
dispatch_async(dispatch_get_main_queue(), ^{
completion(returnedData, nil);
});
}
}];
[uploadTask resume];
}
You'd then call this serverRequest method, specifying precisely what you want to do with the data you receive:
[self serverRequest:url withDictionary:dictionary completion:^(id responseObject, NSError *error) {
if (responseObject) {
// do what you want with the response object here
} else {
NSLog(#"%s: serverRequest error: %#", __FUNCTION__, error);
}
}];
Clearly, you can change this as you see fit, but hopefully this illustrates the idea. If, for example, you knew that responseObject was always going to be a NSDictionary, then I'd change the references to id responseObject with NSDictionary *responseObject.
But the idea is that you should just provide a block that takes the response data and/or the error as parameters. That way, the code that calls this method can specify what should happen when the asynchronous network request completes.
So the call is asynch so you can't really do it like that. What I tend to do is wait for the method to return on its own and then get the main thread (as you've done) and then update UI/models etc like that.