我使用BFTasks在后台执行一些SpriteKit绘图,但我不确定是否正确使用它们,因为绘图正在锁定主线程。
每个对象都由几个SKSpriteNodes组成,这些对象在呈现之前是扁平的。我希望每个线程在被平放后立即呈现,即当我调用[self addChild:miniNode];时,但它等待直到创建完所有线程(锁定主线程),然后它们立即出现。
我简化了下面的代码,以显示任务链:
- (void)drawLocalRelationships
{
[ParseQuery getLocalRelationships:_player.relationships block:^(NSArray *objects, NSError *error) {
[[[self drawRelationships:objects forMini:_player]
continueWithBlock:^id(BFTask *task) {
//this continues once they've all been drawn and rendered
return nil;
}];
}];
}
- (BFTask *)drawRelationships:(NSArray *)relationships forMini:(Mini *)mini
{
return [_miniRows drawSeriesRelationships:relationships forMini:mini];
}MiniRows类:
- (BFTask *)drawSeriesRelationships:(NSArray *)relationships forMini:(Mini *)mini
{
BFTask *task = [BFTask taskWithResult:nil];
for (Relationship *relationship in relationships) {
task = [task continueWithBlock:^id(BFTask *task) {
return [self drawRelationship:relationship mini:mini];
}];
}
return task;
}
- (BFTask *)drawRelationship:(Relationship *)relationship mini:(Mini *)mini
{
//code to determine 'row'
return [row addMiniTask:otherMini withRelationship:relationship];
}排级:
- (BFTask *)addMiniTask:(Mini*)mini withRelationship:(Relationship *)relationship
{
//drawing code
MiniNode *miniNode = [self nodeForMini:mini size:size position:position scale:scale];
[self addChild:miniNode]; //doesn't actually render here
return [BFTask taskWithResult:nil];
}我尝试过在后台线程上运行addMiniTask方法,但这似乎没有什么区别。我想知道我是否误解了BFTasks的概念--我认为它们是在后台线程上自动运行的,但可能不是吗?
发布于 2016-01-26 16:00:54
默认情况下,BFTasks不会在后台线程上运行!
如果你这样做了:
BFTask * immediateTask = [BFTask taskWithResult: @"1"];immediateTask立即在当前线程中完成,即已完成的属性为YES。
此外,如果你这样做了:
[task continueWithBlock:^id(BFTask *task) {
// some long running operation
return nil;
}];一旦任务完成,块将在默认的executor中执行,除非调用堆栈太深,否则它将立即在当前线程中执行块,然后将其卸载到后台调度队列中。当前线程是调用continueWithBlock的线程。因此,除非在后台线程中调用前面的代码,否则长时间运行的操作将阻塞当前线程。
但是,可以使用显式执行器将块卸载到不同的线程或队列:
BFTask * task = [BFTask taskFromExecutor:executor withBlock:^id {
id result = ...; // long computation
return result;
}];选择合适的执行者至关重要:
根据遗嘱执行人的不同,你会有不同的行为。
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,每次获取一个sprite时,您都可以这样做:
- (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
https://stackoverflow.com/questions/34883650
复制相似问题