このトピックについて多くの混乱があり、結果として NSOperation サブクラスのデバッグに数時間を費やしたため、この質問を投稿しました。
問題は、非同期コールバックが完了するまで実際には完了しない非同期メソッドを実行すると、NSOperation があまり役に立たないことです。
NSOperation 自体がコールバック デリゲートである場合、コールバックが別のスレッドで発生するため、操作を適切に完了するのに十分ではない場合もあります。
メイン スレッドで NSOperation を作成し、それを NSOperationQueue に追加すると、NSOperation 内のコードが非同期呼び出しを起動し、AppDelegate またはビュー コントローラーのメソッドにコールバックするとします。
メイン スレッドをブロックできないか、UI がロックされるため、2 つのオプションがあります。
1) NSOperation を作成し、次の署名を使用して NSOperationQueue に追加します。
[NSOperationQueue addOperations:@[myOp] waitUntilFinished:?]
頑張ってください。非同期操作は通常ランループを必要とするため、NSOperation をサブクラス化するかブロックを使用しない限り機能しませんが、コールバックが終了したときに NSOperation を「完了する」必要がある場合は、ブロックでさえ機能しません。
したがって...次のようなもので NSOperation をサブクラス化して、コールバックが操作の完了を通知できるようにします。
//you create an NSOperation subclass it includes a main method that
//keeps the runloop going as follows
//your NSOperation subclass has a BOOL field called "complete"
-(void) main
{
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
//I do some stuff which has async callbacks to the appDelegate or any other class (very common)
while (!complete && [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
}
//I also have a setter that the callback method can call on this operation to
//tell the operation that its done,
//so it completes, ends the runLoop and ends the operation
-(void) setComplete {
complete = true;
}
//I override isFinished so that observers can see when Im done
// - since my "complete" field is local to my instance
-(BOOL) isFinished
{
return complete;
}
OK - これは絶対に機能しません - 邪魔にならないようにしました!
2)このメソッドの 2 番目の問題は、runLoops を適切に終了する必要がある場合 (または、コールバックの外部メソッド呼び出しから実際に終了する場合) に、上記が実際に機能した (実際には機能しない) ことです。
これを呼び出すときに、メイン スレッドで 2 番目の Im を想定してみましょう。UI を少しロックして何も描画しないようにする場合を除き、NSOperationQueue addOperation メソッドで「waitUntilFinished:YES」とは言えません...
では、メイン スレッドをロックせずに、waitUntilFinished:YES と同じ動作を実現するにはどうすればよいでしょうか。
Cocoa での runLoops、NSOperationQueues、Asynch の動作に関して非常に多くの質問があるため、この質問に対する回答として私の解決策を投稿します。
meta.stackoverflow を確認したところ、これは許容可能であり、推奨されているため、私は自分の質問にのみ答えていることに注意してください。コールバック。(他のスレッドでのコールバック)