2

ユーザーに表示する前に、APIからデータをダウンロードしようとしています。

これが私がしていることです:

dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{

    __block NSMutableArray *newImages;

    dispatch_sync(concurrentQueue, ^{
        newImages = [NSMutableArray array];
        // images retrieved using `NSURLConnection sendSynchronousRequest`
    });

    dispatch_sync(dispatch_get_main_queue(), ^{
        // display images to the user
    });
});

私の質問は、newImagesで宣言されているので、メインキューで2番目のタスクを実行するとき__blockに常に最新のデータを持っていることが保証されていますか?newImagesそうでない場合、その配列のコンテンツを2番目のブロックに渡し、最新のコンテンツを確認するための最も安全な方法は何ですか?

私のデータはどこかでめちゃくちゃになっていると思うので、なぜ私はこれを求めています。

これで問題がない場合は、他に問題が発生した場合に備えて、コード全体を投稿して全体をサポートします。

4

4 に答える 4

2

ソリューションのスケッチ:

q = /* custom serial queue */
urls = /* urls array */;
NSMutableArray *images = [NSMutableArray new];
for (NSURL *url in URLs) {
   NSURLRequest *req = [self imageRequestForURL:url];
   dispatch_async(q, ^{
     UIImage *image = [self imageFromRequest:req];
     [images addObject:newImage];
   }
}
dispatch_async(q, ^{
   dispatch_async(dispatch_get_main_queue(), ^{
     [self applyUpdatesForURLs:urls withImages:images];
   });
}

キューは標準の作業キューです。

ブロックは、イメージのapplyUpdatesForURLs:withImages:ダウンロードブロック後にシリアルキューにエンキューされるため、すべてのイメージがダウンロードされた後に実行されることが保証されています。

imagesで動作するすべてのコードが同時にではなくシリアルに実行されるため、同期の問題はありません。

そして、UIの更新は最終的にメインスレッドで行われます。

于 2012-10-01T23:43:12.850 に答える
1

投稿されたメソッドは非常に複雑に見えます。NSURLConnectionメソッドsendAsynchronousRequest:queue:completionHandler:を使用しないのはなぜですか。UIを更新するためのキューパラメータとしてmainQueueを指定できます。

    NSURL *url = [NSURL URLWithString:@"your server address"];
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:5];
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *theData, NSError *error){
        if (error == nil) {
            //do what you want with theData and update the UI
        }
    }];
于 2012-10-01T21:17:16.893 に答える
1

可変配列を更新する同時キューに複数のブロックを含めることはできません。可変コンテナはスレッドセーフではないため、正しく機能しません。画像が利用可能になったら、メインキューのブロックをキューに入れ、代わりにそのアレイに追加します。

于 2012-10-01T21:21:42.697 に答える
1

dispatch_sync()まず、並行キューに入れることはできません。(まあ、できますが、それは。とまったく同じdispatch_async()です。)dispatch_sync()シリアルキューでは、「すべてのブロックがキューに入れられるまで待ってから、このブロックを実行する」と言っている場合にのみ、概念的に意味があります。 、次に制御を呼び出し元のスレッドに戻します。」

第二に、rdelmarの答えは正しいです-あなたはこれを過度に複雑にしています。でバッチ完了ハンドラーを使用したくない場合でもNSURLConnection、並行キューに2つのブロックディスパッチをネストする必要はありません。ネストされた状態でバッチダウンロード(並行キューで非同期を実行)を実行する1つのブロックだけです。完了時にメインキューでUIの更新を行うブロックは問題ありません!

于 2012-10-01T23:25:24.710 に答える