10I've followed a few posts on SOF regarding async calls using GCD and this works fine IF the remote server response is quick enough ,like when working and testing against a local test server.
SOF solutions attempted:
Waiting until two async blocks are executed before starting another block
iPhone - Grand Central Dispatch main thread
Now that I have a remote server set up its taking at least 8 seconds to return its JSON data and the GCD code is acting as if its not waiting for the async call to finish before it updates the UI and I end up with a table view that is empty.
The only way I can get this to behave correctly is by leaving in the line
[NSThread sleepForTimeInterval:10.0];
which forces the app to wait 10 seconds and allows "[self runUnirestRequest:requestUrl];" to return with data, then I get data back. This is obviously a hack and would like to get my GCD code working properly.
Is there any way to make the UI code only execute once the async call has returned with data?
Note: Data returned from runUnirestRequest is in JSON format and is deserialized and placed into an instance of "salesData".
My code related to GCD calls is as follows:
- (void)viewDidLoad
{
...unrelated code...
[self createActivityIndicator];
dispatch_queue_t jsonQueue = dispatch_queue_create("com.ppos.pbsdashboard", NULL);
// Start block on background queue so the main thread is not frozen
// which prevents apps UI freeze
[activityIndicator startAnimating];
dispatch_async(jsonQueue, ^{
// Run remote RESTful request
[self runUnirestRequest:requestUrl];
// Force main thread to wait a bit to allow ansync dispatch
// to get its response with data
[NSThread sleepForTimeInterval:10.0];
// Everything in background thread is done.
// Call another block on main thread to do UI stuff
dispatch_sync(dispatch_get_main_queue(), ^{
// Back within main thread
[activityIndicator stopAnimating];
PBSVCDataDisplay *dataVc = [[PBSVCDataDisplay alloc] init];
[dataVc setSalesData:salesData];
[self performSegueWithIdentifier:@"showDataChart" sender:self];
});
});
}
runUnirestRequest function
- (void) runUnirestRequest:(NSString*)urlToSendRequestTo
{
[requestVCMessages setTextAlignment:NSTextAlignmentCenter];
[requestVCMessages setText:@"Processing request"];
// Handle errors if any occur and display a friendly user message.
@try{
NSDictionary* headers = @{@"p": settingsPassPhrase};
[[UNIRest get:^(UNISimpleRequest* request) {
[request setUrl:urlToSendRequestTo];
[request setHeaders:headers];
}] asJsonAsync:^(UNIHTTPJsonResponse* response, NSError *error) {
UNIJsonNode *jsonNde = [response body];
NSDictionary *jsonAsDictionary = jsonNde.JSONObject;
salesData = [self deserializeJsonPacket:(NSDictionary*)jsonAsDictionary withCalenderType:[requestParameters calendType]];
}];
}
@catch(NSException *exception){
[requestVCMessages setTextAlignment:NSTextAlignmentLeft];
NSString *errHeader = @"An error has occured.\n\n";
NSString *errName = [exception name];
NSString *errString = nil;
// Compare the error name so we can customize the outout error message
if([errName isEqualToString:@"NSInvalidArgumentException"]){
errString = [errHeader stringByAppendingString:@"The reason for the error is probably because data for an invalid date has been requested."];
}else{
errString = [errHeader stringByAppendingString:@"General exception. Please check that your server is responding or that you have requested data for a valid date."];
}
salesData = nil;
[requestVCMessages setText:errString];
}
}