0

インターネットから取得した画像を画面に表示したい。NSURLConnection を使用してデータを取得する非同期呼び出しを作成し、応答ブロックでコードを呼び出してそれを UIImage オブジェクトに割り当てました。

私の質問は、ブロックの実行後に sleep(1) を呼び出す必要があるのはなぜですか? 呼び出していない場合、画像は画面に描画されません。これを達成するための別のよりエレガントな方法はありますか?

-(void)loadImage:(NSString *)url
{
    NSURL *imageURL = [NSURL URLWithString:url];
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageURL cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:5.0f];
    [NSURLConnection sendAsynchronousRequest:imageRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        if(!connectionError) {
            if(data) {
                //there goes the main thingy
                self.myView.wallpaperImage  = [UIImage imageWithData:data];
                [self.myView setNeedsDisplay];
            } else {
                NSLog(@"No data found at url:%@",url);
            }
        } else {
            NSLog(@"Could not connect to %@",url);
        }
    }];
    sleep(1);
}
4

1 に答える 1

2

これ:

self.myView.wallpaperImage  = [UIImage imageWithData:data];
[self.myView setNeedsDisplay];

sendAsynchronousRequest に渡された NSOperationQueue によって管理されるスレッドで発生しています。これらのメソッドは、メイン スレッドから呼び出す必要があります。あなたのスリープが原因で、メイン スレッドの実行ループが繰り返されている可能性があります。その後、それらの呼び出しが機能しているように見えます。これを修正し、現在のアプローチで発生する他の多くの問題を回避するには、次のようにします。

    [NSURLConnection sendAsynchronousRequest:imageRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        if([data length] > 0) {
            //there goes the main thingy
            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                self.myView.wallpaperImage  = [UIImage imageWithData:data];
                [self.myView setNeedsDisplay];
            }];
        } else {
            // Perform your error handling here.

        }
    }];

これは[NSOperationQueue mainQueue]、libdispatch ではなく、メイン キューからこれらの UIKit 呼び出しを実行するために使用されます。libdispatch は低レベルのインターフェースです。常に高レベルのインターフェース (この場合は NSOperationQueue) を優先することが推奨されるベスト プラクティスです。UIKit は、メイン スレッド (またはキュー) から呼び出された場合にのみ安全です。また、プラットフォームのベスト プラクティスに従うようにエラー処理動作を変更します。呼び出しの結果 (この場合はデータ) を確認し、返されたエラーを処理します。

あなたのコードは実際、ブロックがキャプチャされたオブジェクト (この場合は自己) を保持する理由の良い例です。ここに保持サイクルがなければ、ARCqueueは範囲外になるとすぐに破棄でき、ブロックは決して実行されません。代わりに、保持サイクルのために、ブロックが実行されるまでキューは残ります。

于 2014-06-18T23:19:29.077 に答える