3

In my app when the user presses a button I start a HTTP asynchronous request (using [NSURLConnection sendAsynchronousRequest...]) and change the text of UILabel in the completionHandler block. This change, however, does not take place when the request is concluded and instead happens around 2-3 seconds later. Below is a code snippet that results in this behavior.

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

A similar behavior happens when I attempt to create an UIAlertView inside the 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];
         }
     }];    
}

A small difference, though, is that the screen dims when [alert show] is executed. The alert itself only appears 2-3 seconds later like in the previous scenario.

I'm guessing this is related to how the UI is handled by the app's threads, but I'm not sure. Any guidance on why the delay happens will be greatly appreciated.

4

3 に答える 3

9

The Apple Docsによると。

スレッドとユーザー インターフェイス

アプリケーションにグラフィカル ユーザー インターフェースがある場合は、ユーザー関連のイベントを受け取り、アプリケーションのメイン スレッドからインターフェースの更新を開始することをお勧めします。このアプローチは、ユーザー イベントの処理とウィンドウ コンテンツの描画に関連する同期の問題を回避するのに役立ちます。Cocoa などの一部のフレームワークでは通常、この動作が必要ですが、そうでないフレームワークでも、メイン スレッドでこの動作を維持すると、ユーザー インターフェイスを管理するためのロジックが簡素化されるという利点があります。

メイン スレッドで UI の更新を呼び出すと、この問題は解決します。UI コードをメイン スレッド (下記) への呼び出しで囲みます。

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

メインスレッドで呼び出しを行う方法は他にもありますが、より単純な GCD コマンドを使用するとうまくいきます。繰り返しますが、詳細については、スレッド化プログラミング ガイドを参照してください。

于 2012-07-08T20:52:31.833 に答える
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];
         });
     }];    
}
于 2012-07-08T20:37:05.613 に答える
2

テキストを設定するメソッドを作成し、ブロック内で呼び出すことができます。

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

セレクターはメインスレッドで呼び出され、実行されます。この助けを願って....

于 2012-07-08T20:47:23.597 に答える