Следует учесть несколько моментов. Во-первых, возможно, вам следует предпринять усилия, чтобы не перенаправлять из основного потока в основной поток, чтобы ваш -method3
, возможно, выглядел так:
- (void)method3
{
dispatch_block_t work = ^{
// The actual work that method3 does
};
if ([NSThread isMainThread])
work();
else
dispatch_async(dispatch_get_main_queue(), work);
}
У меня есть пара "переходных" функций, которые я иногда использую для этого. Они здесь:
// If we're already on a background thread, just do it now, otherwise dispatch_async
void ensure_bg_thread_trysync(dispatch_block_t block)
{
if (![NSThread isMainThread])
{
block();
}
else
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);
}
}
// If we're already on the main thread, just do it now, otherwise dispatch_async
void ensure_main_thread_trysync(dispatch_block_t block)
{
if ([NSThread isMainThread])
{
block();
}
else
{
dispatch_async(dispatch_get_main_queue(), block);
}
}
Что касается объединения ваших операций друг за другом, есть несколько вариантов. Стиль прохождения продолжения немного неуклюжий в Objective-C, но его можно разумно использовать. Идея здесь в том, что ваши методы возвращают void
и принимают параметр блока «что делать дальше». Итак, ваш пример с -method3
, адаптированным для использования CPS, может выглядеть так (с использованием вышеуказанных функций для удобства:
- (void)method3AndThen: (dispatch_block_t)continuation
{
ensure_main_thread_trysync(^{
// The actual work that method3 does
// ...
// Then call the next thing...
if (continuation) continuation();
};
}
dispatch_async(queue, ^{
[self method1];
[self method2];
[self method3AndThen: ^{
ensure_main_thread_trysync(^{
// Update UI
});
}];
});
Другой вариант, более целеустремленный, заключался бы в использовании NSOperationQueue
и NSOperation
, которые имеют встроенную поддержку цепочки зависимостей между очередями. Ваш пример может выглядеть так, используя NSOperation
s:
NSOperation* op1 = [NSBlockOperation blockOperationWithBlock:^{ [self method1]; }];
NSOperation* op2 = [NSBlockOperation blockOperationWithBlock:^{ [self method2]; }];
NSOperation* op3 = [NSBlockOperation blockOperationWithBlock:^{ [self method3]; }];
NSOperation* updateUIOp = [NSBlockOperation blockOperationWithBlock:^{
NSParameterAssert([NSThread isMainThread]);
NSLog(@"Updating UI on Main Thread");
}];
[updateUIOp addDependency: op1];
[updateUIOp addDependency: op2];
[updateUIOp addDependency: op3];
NSOperationQueue* bgQueue = [NSOperationQueue new];
[bgQueue addOperation: op1]; // Background Thread
[bgQueue addOperation: op2]; // Background Thread
[[NSOperationQueue mainQueue] addOperation: op3]; // Main thread
[[NSOperationQueue mainQueue] addOperation: updateUIOp]; // Main thread
Примечание. Этот код предполагает, что -method1
, -method2
и -method3
могут выполняться одновременно друг с другом. Если они должны выполняться последовательно, вы просто добавляете зависимости между ними, например: [op2 addDependency: op1]; [op3 addDependency: op2];
GCD - это новая популярность, и поэтому в наши дни ему, как правило, уделяется больше эфирного времени, но _15 _ / _ 16_ довольно мощный (не говоря уже о том, что они реализованы поверх GCD)
person
ipmcc
schedule
03.02.2015