Ios 主线程未等待异步完成

Ios 主线程未等待异步完成,ios,multithreading,asynchronous,unirest,Ios,Multithreading,Asynchronous,Unirest,10我已经关注了一些关于使用GCD进行异步调用的SOF帖子,如果远程服务器响应足够快,比如在本地测试服务器上工作和测试时,这种方法就可以很好地工作 尝试的SOF解决方案: 现在,我已经设置了一个远程服务器,它需要至少8秒的时间来返回JSON数据,GCD代码的作用就像它在更新UI之前没有等待异步调用完成一样,我最终得到了一个空的表视图 我唯一能让它正常运行的方法就是排队 [NSThread sleepForTimeInterval:10.0]; 这会迫使应用程序等待10秒,并允许“[self

10我已经关注了一些关于使用GCD进行异步调用的SOF帖子,如果远程服务器响应足够快,比如在本地测试服务器上工作和测试时,这种方法就可以很好地工作

尝试的SOF解决方案:

现在,我已经设置了一个远程服务器,它需要至少8秒的时间来返回JSON数据,GCD代码的作用就像它在更新UI之前没有等待异步调用完成一样,我最终得到了一个空的表视图

我唯一能让它正常运行的方法就是排队

[NSThread sleepForTimeInterval:10.0];
这会迫使应用程序等待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];
    });
});
}
运行unirestrequest函数

- (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];
}
}

这不是使用异步调用的方式。您在这里所做的是接受异步调用并使其同步

异步代码不应该关心调用是花费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请求的已异步调用包装到另一个异步块中


只需使用请求已经是异步的这一事实。

因为您的
runUnirestRequest
是aync。然后在
dispatch\u async
语句中调用它
[self-runUnirestRequest:requestUrl]
执行不会等到
runUnirestRequest
完成。您应该改为更改
runUnirestRequest
sync。这可能会解决您的问题。

请看另一个问题谢谢您的回答,我确实尝试过,而且效果完全相同。删除sleepForTimeInterval调用还会添加错误“嵌套推送动画可能导致导航栏损坏”,另外两个错误与“”调用相关。是否存在用于分派\u async的onComplete块?似乎找不到类似的内容。runUnirestRequest中有什么内容?对于
onComplete
您应该使用操作队列,而不是GDC队列。您是否可以显示runUnirestRequest的实际功能,因为您可以将UIcode作为完成块传入或将其分配给变量。如果你展示了代码的工作原理,很高兴能解释更多。Re:“嵌套的推送动画会导致导航栏损坏”。我认为调用
performsguewithidentifier
,即使您不知道这个viewController是否可见,也可能是造成这种情况的原因。我认为您应该考虑将一些代码放入
viewdide
中,而不是
viewdideload
@Fogmeister将
asJsonAsync
替换为
asJson
可能会修复。我意识到这可能会起作用,但在异步调用已经是异步的情况下,使其工作起来会增加很多复杂性。所以只要去掉围绕它的额外复杂性,它就已经是异步的了。@Fogmeister是的,你是对的。我只是给出另一个解决方案。干杯,福格迈斯特,这很好地解释了/指出了我的错误。非常感谢。