如何停止主 ui 线程,直到我得到来自 http 请求的响应

Posted

技术标签:

【中文标题】如何停止主 ui 线程,直到我得到来自 http 请求的响应【英文标题】:How to stop main ui thread until i get response from http request 【发布时间】:2017-04-20 10:41:02 【问题描述】:

我的目标场景: 尝试向我的应用程序服务器发送一个简单的 HTTP 请求并获得一个 json 响应作为回报。根据 json 响应,我需要执行 segue 操作。

我目前的情景: 这发生在我的系统中。经过太多延迟后,我的 HTTP 请求得到了 json 响应,因为我的响应是在延迟之后执行的,甚至没有检查响应中的数据就执行了 segue。

我的要求 如何让我的 segue 等到我收到 HTTP 请求的响应?

[application getjsonResponse];
     if([[defaults stringForKey:@"status"] isEqual:@"success"])
        

            return YES;

        

这些是我使用的代码行。我不希望我的线程执行这个 if 条件,除非我得到对我的 HTTP 请求的响应。

到目前为止我尝试过的

    我尝试了线程睡眠方法,它有时有效,有时无效。 在我得到响应之前,我会迭代一个 while 循环。

好奇的问题 当我从桌面浏览器 (Chrome) 或移动浏览器向我的应用程序发出相同的请求时,我会立即得到响应,但是当我使用代码时,我似乎会在 10 秒或更长时间后得到结果。这是为什么呢?

这是我用来向我的应用服务器发送 http 请求的一段代码。

-(void)getjsonResponse

NSURL *url=[NSURL URLWithString: URLForApplication];
NSURLRequest *req=[NSURLRequest requestWithURL:url];
NSURLSession *session = [NSURLSession sharedSession];

NSURLSessionDataTask connection=[session dataTaskWithRequest:req completionHandler:^(NSData data, NSURLResponse response, NSError error)
 
     if (!error)
                                     // Success
            if ([response isKindOfClass:[NSHTTPURLResponse class]])
            
                NSError *jsonError;
                NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
                if (jsonError)
                                       // Error Parsing JSON
                
                else
                   // Success Parsing JSON
                    // Log NSDictionary response:                                                      
                    NSLog(@"%@",jsonResponse);
                                         
                        NSString * statusCode=[[NSString alloc]init];
                        statusCode=jsonResponse[@"statusCode"];
                        _statusOtpResponse=jsonResponse[@"status"];
                        NSLog(@"status value: %@",_statusOtpResponse);
                        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
                        [defaults setObject:_statusOtpResponse forKey:@"status"];
                        [defaults setObject:statusCode forKey:@"statuscodeOtp"];
                        [defaults synchronize];                                           
                    
                
            
            else
            
                                                  //Web server is returning an error
            
        
        else
        
                                              // Fail
                                              NSLog(@"error : %@", error.description);
        

    ];
        if(connection)
            [connection resume];
        

【问题讨论】:

所以请使用正确的语法。此外,停止 UI 线程通常是一个非常糟糕的主意 - 它会使 GUI 响应并让用户认为应用程序可能崩溃了。 @tambre 所以我不想停止 ui 线程如何让 ui 线程等到我从 http 请求中得到响应请帮忙.. 【参考方案1】:

好的。你的问题有很多矛盾之处。例如,您谈论执行 segue,但您的代码不包含任何执行此操作的内容。

无论如何,首先我要说的是,停止/暂停应用程序的主线程是个坏主意。时期。当您执行此类操作时,或以任何方式在主线程上运行需要大量时间来执行的代码时,您实际上会使您的应用程序无响应,并且无响应的应用程序被用户视为质量差,因此不值得使用。

以下是我将如何重写您的代码以执行 segue。注意主线程上的回调。

NSURL *url = [NSURL URLWithString: URLForApplication];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
NSURLSession *session = [NSURLSession sharedSession];

// Do something here to indicate a server query is executing.
// For example, displaying a UIActivityIndicatorView

// Note: you had a missing '*' on this line
NSURLSessionDataTask *connection = [session dataTaskWithRequest:req completionHandler:^(NSData data, NSURLResponse response, NSError error) 

    // First error check. 
    if (error) 
        // Log and/or display alert with error message and finish.
        // Reset display to non busy mode on main thread.
        NSLog(@"error : %@", error.description);
        return;
    

    // We're here, so request was a success
    if ([response isKindOfClass:[NSHTTPURLResponse class]]) 

        NSError *jsonError;
        NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
        if (jsonError) 
            // Log and/or display alert with error message and finish.
            // Reset display to non busy mode on main thread.
            NSLog(@"error : %@", error.description);
            return;
        

        // We're here, so JSON parse was a success
        NSLog(@"%@", jsonResponse);
        NSString *statusCode = jsonResponse[@"statusCode"];
        NSString *statusOtpResponse = jsonResponse[@"status"];
        if (/* test variables to decide if to execute the segue */) 

            // Now we know we want to execute the segue.
            dispatch_async(dispatch_get_main_queue(), ^
                [self performSegueWithIdentifier:@"segue-id" sender:self];
            );
        

        // Removed your code for storing response codes in user defaults because I simply could not see why you would do that.
    ];

    // Execute
    [connection resume];

```

【讨论】:

感谢回复..我使用 userdefaults 存储来自 jsonresponse 的值,我尝试从视图控制器中 userdefault 的 jsonresponses 中获取值,然后执行 segue。【参考方案2】:

NSURLSessionDataTask 已经被系统异步执行了。

因此,如果您想在收到请求的数据后执行转场,只需将转场代码放在完成块中即可。

在您的情况下,就在您处理响应数据之后,例如在以下行之后:

[defaults synchronize];  

请注意,在再次在主线程上工作之前,您应该先分派到主线程。

dispatch_async(dispatch_get_main_queue(), ^
   // YOUR SEGUE HERE
);

【讨论】:

以上是关于如何停止主 ui 线程,直到我得到来自 http 请求的响应的主要内容,如果未能解决你的问题,请参考以下文章

在主线程上处理大型全局对象时如何不阻止来自工作线程的主 UI 线程

从 ui-thread 显示窗口有时会阻塞主 ui-thread

如何在单个 catch 块中处理来自工作线程和主线程的异常?

再次运行应用程序时如何停止关闭的应用程序留下的线程? C#

boost - thread.join() 停止用户界面

如何在 C# 中按下停止按钮来停止耗时过长的 UI 线程 [关闭]