デフォルトでは、BFTask はバックグラウンド スレッドでは実行されません。
もしあなたがそうするなら:
BFTask * immediateTask = [BFTask taskWithResult: @"1"];
immediateTask は現在のスレッドですぐに完了します。つまり、completed プロパティは YES です。
また、次の場合:
[task continueWithBlock:^id(BFTask *task) {
// some long running operation
return nil;
}];
タスクが完了すると、ブロックはデフォルトのエグゼキュータで実行されます。コール スタックが深すぎない限り、ブロックは現在のスレッドですぐに実行されます。深い場合はバックグラウンド ディスパッチ キューにオフロードされます。現在のスレッドは、continueWithBlock が呼び出されたスレッドです。そのため、バックグラウンド スレッドで前のコードを呼び出していない限り、実行時間の長い操作によって現在のスレッドがブロックされます。
ただし、明示的なエグゼキューターを使用して、ブロックを別のスレッドまたはキューにオフロードできます。
BFTask * task = [BFTask taskFromExecutor:executor withBlock:^id {
id result = ...; // long computation
return result;
}];
適切なエグゼキューターを選択することが重要です。
- executor = [BFExecutor defaultExecutor] タスクのブロックは現在のスレッド (タスクの作成が実行されるスレッド) で実行されるか、コール スタックが深すぎる場合はバックグラウンド キューにオフロードされます。そのため、何が起こるかを予測するのは困難です。
- executor = [BFExecutor immediateExecutor] タスクのブロックは、前のタスクと同じスレッドで実行されます (以下の連鎖を参照)。しかし、前のタスクがデフォルトのエグゼキューターによって実行された場合、それがどのスレッドであるかはわかりません。
- executor = [BFExecutor mainThreadExecutor] タスクのブロックはメイン スレッドで実行されます。これは、長時間実行された操作の後に UI を更新するために使用するものです。
- executor = [BFExecutor executorWithDispatchQueue:gcd_queue] タスクのブロックは、指定された gcd キューで実行されます。実行時間の長い操作を実行するには、バックグラウンド キューを使用してキューを作成します。キューのタイプ (シリアルまたはコンカレント) は、実行するタスクとその依存関係によって異なります。
エグゼキュータに応じて、異なる動作が得られます。
BFTasks の利点は、異なるスレッドで実行されているタスクをチェーンして同期できることです。たとえば、バックグラウンド操作を長時間実行した後にメイン スレッドで UI を更新するには、次のようにします。
// From the UI thread
BFTask * backgroundTask = [BFTask taskFromExecutor:backgroundExecutor withBlock:^id {
// do your long running operation here
id result = ...; // long computation here
return result;
}];
[backgroundTask continueWithExecutor:[BFExecutor mainThreadExecutor] withSuccessBlock:^id(BFTask* task) {
id result = task.result;
// do something quick with the result - we're executing in the UI thread here
return nil
}];
PFQuery の findInBackgroundWithBlock メソッドはデフォルトのエグゼキュータでブロックを実行するため、メイン スレッドからそのメソッドを呼び出すと、ブロックもメイン スレッドで実行される可能性が高くなります。あなたの場合、SpriteKit については何も知りませんが、すべてのスプライトを取得してから UI を更新します。
- (void)queryRenderAllUpdateOnce {
NSThread *currentThread = [NSThread currentThread];
NSLog(@"current thread is %@ ", currentThread);
// replace the first task by [query findObjectsInBackground]
[[[BFTask taskFromExecutor:[Tasks backgroundExecutor] withBlock:^id _Nonnull{
NSLog(@"[%@] - Querying model objects", [NSThread currentThread]);
return @[@"Riri", @"Fifi", @"LouLou"];
}] continueWithExecutor:[BFExecutor immediateExecutor] withBlock:^id _Nullable(BFTask * _Nonnull task) {
NSLog(@"[%@] - Fetching sprites for model objects", [NSThread currentThread]);
NSArray<NSString *> * array = task.result;
NSMutableArray * result = [[NSMutableArray alloc] init];
for (NSString * obj in array) {
// replace with sprite
id sprite = [@"Rendered " stringByAppendingString:obj];
[result addObject:sprite];
}
return result;
}] continueWithExecutor:[BFExecutor mainThreadExecutor] withBlock:^id _Nullable(BFTask * _Nonnull task) {
NSLog(@"[%@] - Update UI with all sprite objects: %@", [NSThread currentThread], task.result);
// TODO update the UI here.
return nil;
}];
}
しかし、このソリューションでは、すべてのスプライトがフェッチ (フラット化?) されてから、UI が更新されます。UI を更新したい場合は、スプライトがフェッチされるたびに、次のようにすることができます。
- (void)queryRenderUpdateMany {
NSThread *currentThread = [NSThread currentThread];
NSLog(@"current thread is %@ ", currentThread);
[[[BFTask taskFromExecutor:[Tasks backgroundExecutor] withBlock:^id _Nonnull{
NSLog(@"[%@] - Querying model objects", [NSThread currentThread]);
return @[@"Riri", @"Fifi", @"LouLou"];
}] continueWithExecutor:[BFExecutor immediateExecutor] withBlock:^id _Nullable(BFTask * _Nonnull task) {
NSArray<NSString *> * array = task.result;
NSMutableArray * result = [[NSMutableArray alloc] init];
for (NSString * obj in array) {
BFTask *renderUpdate = [[BFTask taskFromExecutor:[BFExecutor immediateExecutor] withBlock:^id _Nonnull{
NSLog(@"[%@] - Fetching sprite for %@", [NSThread currentThread], obj);
return [@"Rendered " stringByAppendingString:obj];
}] continueWithExecutor:[BFExecutor mainThreadExecutor] withBlock:^id _Nullable(BFTask * _Nonnull task) {
NSLog(@"[%@] - Update UI with sprite %@", [NSThread currentThread], task.result);
return nil;
}];
[result addObject: renderUpdate];
}
return [BFTask taskForCompletionOfAllTasks:result];
}] continueWithExecutor:[BFExecutor mainThreadExecutor] withBlock:^id _Nullable(BFTask * _Nonnull task) {
NSLog(@"[%@] - Updated UI for all sprites", [NSThread currentThread]);
return nil;
}];
}
ここで、中間タスクは、すべての renderUpdate タスクが完了すると完了するタスクを作成します。
この助けを願っています。
B