【问题标题】:Delay when updating view in the completionHandler of an async HTTP request在异步 HTTP 请求的 completionHandler 中更新视图时出现延迟
【发布时间】:2012-07-08 20:23:15
【问题描述】:

在我的应用程序中,当用户按下按钮时,我会启动 HTTP 异步请求(使用 [NSURLConnection sendAsynchronousRequest...])并更改 completionHandler 块中 UILabel 的文本。但是,此更改不会在请求结束时发生,而是在大约 2-3 秒后发生。下面是导致这种行为的代码 sn-p。

- (IBAction)requestStuff:(id)sender 
{
    NSURL *url = [NSURL URLWithString:@"http://stackoverflow.com/"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];

    [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:
     ^(NSURLResponse *response, NSData *data, NSError *error) 
     {
         NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;          
         exampleLabel.text = [NSString stringWithFormat:@"%d", httpResponse.statusCode];
     }];    
}

当我尝试在completionHandler 中创建UIAlertView 时,会发生类似的行为。

- (IBAction)requestStuff:(id)sender 
{
    NSURL *url = [NSURL URLWithString:@"http://stackoverflow.com/"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];

    [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:
     ^(NSURLResponse *response, NSData *data, NSError *error) 
     {
         NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; 

         if ([httpResponse statusCode] == 200) {
             UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"It worked!" 
                                                             message:nil
                                                            delegate:nil 
                                                   cancelButtonTitle:@"OK"
                                                   otherButtonTitles:nil];
             [alert show];
             [alert release];
         }
     }];    
}

不过,一个小的区别是在执行[alert show] 时屏幕会变暗。警报本身仅在 2-3 秒后出现,就像之前的场景一样。

我猜这与应用程序线程如何处理 UI 有关,但我不确定。任何有关延迟发生原因的指导将不胜感激。

【问题讨论】:

    标签: objective-c ios nsurlconnection uialertview


    【解决方案1】:

    根据The Apple Docs.

    线程和您的用户界面

    如果您的应用程序具有图形用户界面,建议您从应用程序的主线程接收与用户相关的事件并启动界面更新。 这种方法有助于避免与处理用户事件和绘制窗口内容相关的同步问题。一些框架,例如 Cocoa,通常需要这种行为,但即使对于那些不需要这种行为的框架,将这种行为保留在主线程上也有利于简化管理用户界面的逻辑。

    在主线程上调用你的 UI 更新可以解决这个问题。调用主线程(如下)围绕您的 UI 代码。

    dispatch_async(dispatch_get_main_queue(), ^{
       exampleLabel.text = [NSString stringWithFormat:@"%d", httpResponse.statusCode];
    });
    

    还有其他方法可以在主线程上进行调用,但使用更简单的 GCD 命令就可以完成这项工作。再次,请参阅Threaded Programming Guide 了解更多信息。

    【讨论】:

      【解决方案2】:

      这可能是因为所有 UI 内容都应该在主队列中调用。试试这个:

      - (IBAction)requestStuff:(id)sender 
      {
          NSURL *url = [NSURL URLWithString:@"http://stackoverflow.com/"];
          NSURLRequest *request = [NSURLRequest requestWithURL:url];
          NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];
      
          [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:
           ^(NSURLResponse *response, NSData *data, NSError *error) 
           {
               NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;          
      
               dispatch_async(dispatch_get_main_queue(), ^{
                   exampleLabel.text = [NSString stringWithFormat:@"%d", httpResponse.statusCode];
               });
           }];    
      }
      

      【讨论】:

        【解决方案3】:

        您可以尝试创建一个设置文本的方法,并在您调用的块内:

                [self performSelectorOnMainThread:@selector(mySelector) withObject:nil waitUntilDone:NO];
        

        选择器将在主线程上调用和执行。希望对您有所帮助....

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-02-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-08-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多