私はいくつかの関連する質問を見てきましたが、誰もこのケースに答えるようには見えません。バックグラウンドで動作するメソッドを記述したいと思います。元のメソッド呼び出しに使用したのと同じスレッド/キューで完了コールバックを呼び出すには、このメソッドが必要です。
- (void)someMethod:(void (^)(BOOL result))completionHandler {
dispatch_queue_t current_queue = // ???
// some setup code here
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
BOOL ok = // some result
// do some long running processing here
dispatch_async(current_queue, ^{
completionHandler(ok);
});
});
sameMethod
の呼び出しと同じキューまたはスレッドで完了ハンドラーが呼び出されるように、ここではどの魔法の呪文が必要ですか?メインスレッドを想定したくありません。そしてもちろん dispatch_get_current_queue
は使用されません。
Apple docsを見ると、2つのパターンがあるように見えます。
完了ハンドラーがメインスレッドで実行されることが想定されている場合、キューを提供する必要はありません。例は、UIView
のanimations
メソッドです。
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion
それ以外の場合、APIは通常、呼び出し元にキューを提供するように要求します。
[foo doSomethingWithCompletion:completion targetQueue:yourQueue];
私の提案は、このパターンに従うことです。完了ハンドラーを呼び出す必要があるキューが明確でない場合、呼び出し元はそれをパラメーターとして明示的に指定する必要があります。
メインキューは別として、特定のスレッドで実行されることが保証されていないため、実際にはキューを使用できません。代わりに、スレッドを取得してブロックを直接実行する必要があります。
Mike Ash's Block Additions からの適応:
_// The last public superclass of Blocks is NSObject
@implementation NSObject (rmaddy_CompletionHandler)
- (void)rmaddy_callBlockWithBOOL: (NSNumber *)b
{
BOOL ok = [b boolValue];
void (^completionHandler)(BOOL result) = (id)self;
completionHandler(ok);
}
@end
_
_- (void)someMethod:(void (^)(BOOL result))completionHandler {
NSThread * origThread = [NSThread currentThread];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
BOOL ok = // some result
// do some long running processing here
// Check that there was not a nil handler passed.
if( completionHandler ){
// This assumes ARC. If no ARC, copy and autorelease the Block.
[completionHandler performSelector:@selector(rmaddy_callBlockWithBOOL:)
onThread:origThread
withObject:@(ok) // or [NSNumber numberWithBool:ok]
waitUntilDone:NO];
}
});
});
_
dispatch_async()
を使用していませんが、元のディスパッチされたタスクブロック内に含まれているため、これはプログラムの残りの部分に関しては非同期です。また、_waitUntilDone:NO
_は、それ。
これで問題が解決するかどうかはわかりませんが、GCDの代わりにNSOperationsを使用するのはどうですか?:
- (void)someMethod:(void (^)(BOOL result))completionHandler {
NSOperationQueue *current_queue = [NSOperationQueue currentQueue];
// some setup code here
NSOperationQueue *q = [[NSOperationQueue alloc] init];
[q addOperationWithBlock:^{
BOOL ok = YES;// some result
// do some long running processing here
[current_queue addOperationWithBlock:^{
completionHandler(ok);
}];
}];
@rmaddyが述べたように、いくつかのキューでいくつかのタスクを実行してから、完了ブロックを実行したいと思っていました。 Apple=から同時実行プログラミングガイドに出会い、これを実装しました(disp_retain&dispatch_releasedはARCを使用しているためコメントアウトされています)- https://developer.Apple.com/ library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html#// Apple_ref/doc/uid/TP40008091-CH102-SW1
void average_async(int *data, size_t len, dispatch_queue_t queue, void (^block)(int))
{
// Retain the queue provided by the user to make
// sure it does not disappear before the completion
// block can be called.
//dispatch_retain(queue); // comment out if use ARC
// Do the work on user-provided queue
dispatch_async(queue, ^{
int avg = average(data, len);
dispatch_async(queue, ^{ block(avg);});
// Release the user-provided queue when done
//dispatch_release(queue); // comment out if use ARC
});
}