更新异步HTTP请求的completionHandler中的视图时出现延迟

时间:2012-07-08 20:23:15

标签: objective-c ios nsurlconnection uialertview

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

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

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

- (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有关,但我不确定。任何有关延迟发生原因的指导将不胜感激。

3 个答案:

答案 0 :(得分:9)

根据The Apple Docs

  

主题和您的用户界面

     

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

在主线程上调用UI更新可以解决此问题。通过调用主线程(下面)来围绕您的UI代码。

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

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

答案 1 :(得分:4)

这可能发生,因为应该在主队列中调用所有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];
         });
     }];    
}

答案 2 :(得分:2)

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

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

选择器将在主线程上调用并执行。希望这有帮助......