10我已经在SOF上发布了一些关于使用GCD进行异步调用的帖子,如果远程服务器响应足够快就可以正常工作,例如在对本地测试服务器进行工作和测试时。
尝试了SOF解决方案:
Waiting until two async blocks are executed before starting another block
iPhone - Grand Central Dispatch main thread
现在我有一个远程服务器设置它至少需要8秒才能返回其JSON数据,并且GCD代码就好像在更新UI之前没有等待异步调用完成,我最终得到了表视图为空。
我能让这种行为正确的唯一方法是留在行
[NSThread sleepForTimeInterval:10.0];
强制app等待10秒并允许“[self runUnirestRequest:requestUrl];”返回数据,然后我得到数据。这显然是一个黑客,并希望我的GCD代码正常工作。
有没有办法让UI代码只在异步调用返回数据后执行?
注意:从runUnirestRequest返回的数据是JSON格式并反序列化并放入“salesData”的实例中。
我的GCD调用代码如下:
- (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函数
- (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];
}
}
答案 0 :(得分:0)
这不是您使用异步调用的方式。你在这里做的是进行异步调用并使其同步。
您的异步代码不应该关心调用是否需要10毫秒,10秒或10分钟。它适用于所有情况。
也许你应该把它设置成......
- (void)viewDidLoad
{
// other stuff...
[self runUnirestRequest:requestUrl];
// other stuff...
}
- (void)runUnirestRequest:(NSString*)urlToSendRequestTo
{
// self.activityIndicator should be a property
// accessible from anywhere in the class
[self.activityIndicator startAnimating];
// don't use try/catch here you already have built in error handling in the call
NSDictionary* headers = @{@"p": settingsPassPhrase};
[[UNIRest get:^(UNISimpleRequest* request) {
[request setUrl:urlToSendRequestTo];
[request setHeaders:headers];
}] asJsonAsync:^(UNIHTTPJsonResponse* response, NSError *error) {
if (error) {
// handle the error here not in a try/catch block
}
UNIJsonNode *jsonNde = [response body];
NSDictionary *jsonAsDictionary = jsonNde.JSONObject;
salesData = [self deserializeJsonPacket:(NSDictionary*)jsonAsDictionary withCalenderType:[requestParameters calendType]];
dispatch_async(dispatch_get_main_queue(), ^{
[self.activityIndicator stopAnimating];
PBSVCDataDisplay *dataVc = [[PBSVCDataDisplay alloc] init];
[dataVc setSalesData:salesData];
[self performSegueWithIdentifier:@"showDataChart" sender:self];
});
}];
}
您似乎在另一个异步块中包装已经异步调用的json请求。
只需使用请求已经异步的事实。
答案 1 :(得分:0)
因为您的runUnirestRequest
是异步的。然后你在dispatch_async
语句中调用它。 [self runUnirestRequest:requestUrl]
执行不会等到runUnirestRequest
完成。您应该更改runUnirestRequest
同步。这可能会解决您的问题。