1

ですから、しばらく前に完了ブロックについて学んだ後、私は完了ブロックをたくさん使うのが好きです。私は閉鎖が好きで、好きな場所に何でも渡すことができるのが好きです。

スレッドプログラミングに不慣れな私は、GCDとNSOperationに近づいていませんでしたが、最近、Core Dataに更新された非同期プログラミングを行う必要があり、「すべての完了ブロック」に常に疑問を抱き始めています。 " アプローチ。

それで、私が自分自身に質問していることの1つの例があります:私はどこかのサーバーにアップロードするための一連の潜在的にかなり大きなデータ(画像、音声、ビデオ、あなたが持っているもの)を持っています。これらのデータのメタデータはCoreDataに保存されており、アップロードするオブジェクトを決定するために使用するタイムスタンプがあります。これらのアップロードはすべて順番に実行する必要があります。

私がコーディングしたのは、基本的には完了ブロックを含む関数であり、次のようにブロックの最後にそれ自体を呼び出します。

(void)uploadAllAsynchronously {
  ... // First figure out what to upload based on core data
  // Here comes the completion block in question
  void(^blk)(BOOL) = ^(BOOL)uploadSuccess {
    ... // if upload successful, update core data to mark what has been uploaded
    [self uploadAllAsynchronously]; // Recursively calls the function that contains this block.  I actually have a weak self, or if that fails to break a retain cycle, I should be able to pass in a NSManagedObjectContext as an argument.
  }
  [NSURLConnection sendAsynchronousRequest:... queue:... completionHandler:blk];


}

これはうまくいくはずですよね?GCDを使用して自分のキューを処理する必要があることを示唆する、完全に危険なものがここにありますか?コードのどの部分が原因かはわかりませんが、現在データに問題があるため、非同期呼び出しのために別のスレッドが正しく更新されていないように見える可能性があるため、これを求めています。

前もって感謝します。

4

2 に答える 2

1

はい、このコードは機能するはずです。注:メソッドの名前を変更します。uploadIfNeeded多分-常に盲目的にコンテンツをアップロードするとは限らないため...

于 2012-12-29T21:51:28.213 に答える
1

ブロックのタイプが間違っています。

ドキュメントとして

+ (void)sendAsynchronousRequest:(NSURLRequest *)request queue:(NSOperationQueue *)queue completionHandler:(void (^)(NSURLResponse *, NSData *, NSError *))handler

ショー、コンプリーションブラックのタイプは

void (^) (NSURLResponse *, NSData *, NSError *)

いいえ

void (^) (BOOL)

あなたはblk次のようなものに変更する必要があります

void (^blk) (NSURLResponse *, NSData *, NSError *) = ^ (NSURLResponse *response, NSData *data, NSError *error) {
    //...
};

書くほうがスタイリッシュだろう

[NSURLConnection sendAsynchronousRequest:theRequest queue:theQueue completionHandler:^ (NSURLResponse *response, NSData *data, NSError *error) {
    //...
}];

メソッドに沿った完了ブロックを使用します。


NSManagedObjectContext完了ハンドラーでの操作の実行に関する質問について:渡先が管理対象オブジェクトのコンテキストが作成されNSOperationQueuesendAsynchronousRequest:queue:completionHandler:ものと同じである限り、これは問題ありません。しかし、州の文書としてNSManagedObjectContext

Core Dataは、スレッド(またはシリアル化されたキュー)の制限を使用して、管理対象オブジェクトと管理対象オブジェクトのコンテキストを保護します(「CoreDataとの同時実行」を参照)。この結果、コンテキストは、デフォルトの所有者がそれを割り当てたスレッドまたはキューであると想定します。これは、initメソッドを呼び出すスレッドによって決定されます。したがって、あるスレッドでコンテキストを初期化してから、それを別のスレッドに渡すことはできません。代わりに、永続ストアコーディネーターへの参照を渡し、受信スレッド/キューにそれから派生した新しいコンテキストを作成させる必要があります。

渡すキューが管理対象オブジェクトコンテキストを作成したキューではない場合は、次のいずれかを実行する必要があります。

  1. -[NSOperationQueue addOperation:]管理対象オブジェクトコンテキストが作成されたキューを呼び出します。

  2. コアデータ操作が行われているキューに、(同じ永続ストアコーディネーターを使用して)2番目の管理対象オブジェクトコンテキストを作成します。

  3. コアデータ操作が行われているキューに、2番目の管理対象オブジェクトコンテキストと2番目の永続ストアコーディネーターを作成します。

  4. ロックを使用します。

Core Dataとの同時実行に関するドキュメントでは、スレッドの制限(上記のオプション1〜3)またはロック(上記のオプション4)のいずれかを使用する必要があることが明確になっています。

これは、ドキュメントがロックの使用について言わなければならないことです:

スレッド封じ込めパターンを使用しないことを選択した場合、つまり、管理対象オブジェクトやコンテキストをスレッド間で受け渡そうとする場合などは、ロックに細心の注意を払う必要があります。その結果、メリットが失われる可能性があります。それ以外の場合は、マルチスレッドから派生する可能性があります。

これは、スレッドごとの管理対象オブジェクトコンテキストだけでなく、スレッドごとの永続ストアコーディネーターも持つことについてドキュメントが言わなければならないことです。

このアプローチでは、複雑さが増し(特に、異なるコンテキスト間で変更を伝達する必要がある場合)、メモリ使用量が増える代わりに、同時実行性が向上します。

于 2012-12-30T01:29:43.883 に答える