Мне было интересно, можете ли вы использовать cancel / cancelAllOperations / .isCancelled с потоком, который вы запустили с GCD?
В настоящее время я просто использую логическое значение в качестве флага, чтобы отменить фоновый процесс.
Допустим, вы хотите много обрабатывать в фоновом режиме, сохраняя при этом интерфейс пользователя отзывчивым, чтобы вы могли поймать кнопку отмены (или анимировать что-то, чтобы показать, что процессор работает).Вот как мы это делаем ...
@interface AstoundingView : UIView
{
BOOL pleaseAbandonYourEfforts;
blah
}
@implementation AstoundingView
//
// these are the foreground routines...
// begin, abandon and all-done
//
-(void)userHasClickedToBuildASpaceship
{
[YourUIStateMachine buildShip];
[self procedurallyBuildEnormousSpaceship];
}
-(void)userHasClickedToAbandonBuildingTheSpaceship
{
[YourUIStateMachine inbetween];
pleaseAbandonYourEfforts = false; // that's it!
}
-(void)attentionBGIsAllDone
{
// you get here when the process finishes, whether by completion
// or if we have asked it to cancel itself.
[self typically setNeedsDisplay, etc];
[YourUIStateMachine nothinghappening];
}
//
// these are the background routines...
// the kickoff, the wrapper, and the guts
//
// The wrapper MUST contain a "we've finished" message to home
// The guts can contain messages to home (eg, progress messages)
//
-(void)procedurallyBuildEnormousSpaceship
{
// user has clicked button to build new spaceship
pleaseAbandonYourEfforts = FALSE;
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),
^{ [self actuallyProcedurallyBuildInBackground]; }
);
// as an aside, it's worth noting that this does not work if you
// use the main Q rather than a global Q as shown.
// Thus, this would not work:
// dispatch_async(dispatch_get_main_queue(), ^{ ...; });
}
-(void)actuallyProcedurallyBuildInBackground
{
// we are actually in the BG here...
[self setUpHere];
// set up any variables, contexts etc you need right here
// DO NOT open any variables, contexts etc in "buildGuts"
// when you return back here after buildGuts, CLEAN UP those
// variables, contexts etc at this level.
// (using this system, you can nest as deep as you want, and the
// one CHECKER pseudocall will always take you right out.
// You can insert CHECKERs anywhere you want.)
[self buildGuts];
// Note that any time 'CHECKER' "goes off', you must fall-
// through to exactly here. This is the common fall-through point.
// So we must now tidy-up, to match setUpHere.
[self wrapUpHere];
// when you get to here, we have finished (or, the user has cancelled
// the background operation)
// Whatever technique you use,
// MAKE SURE you clean up all your variables/contexts/etc before
// abandoning the BG process.
// and then you must do this......
// we have finished. it's critical to let the foreground know NOW,
// or else it will sit there for about 4 to 6 seconds (on 4.3/4.2)
// doing nothing until it realises you are done
dispatch_sync(
dispatch_get_main_queue(),
^{[self attentionBGIsAllDone];} // would setneedsdisplay, etc
);
return;
}
-(void)buildGuts
{
// we are actually in the BG here...
// Don't open any local variables in here.
CHECKER
[self blah blah];
CHECKER
[self blah blah];
CHECKER
[self blah blah];
// to get stuff done from time to time on the UI, something like...
CHECKER
dispatch_sync(
dispatch_get_main_queue(),
^{[supportStuff pleasePostMidwayImage:
[UIImage imageWithCGImage:halfOfShip] ];}
);
CHECKER
[self blah blah];
CHECKER
[self blah blah];
CHECKER
[self blah blah];
for ( i = 1 to 10^9 )
{
CHECKER
[self blah blah];
}
CHECKER
[self blah blah];
CHECKER
[self blah blah];
CHECKER
[self blah blah];
return;
}
и CHECKER ничего не делает, кроме как проверяет, что флаг верен ...
#define CHECKER if ( pleaseAbandonYourEfforts == YES ) \
{NSLog(@"Amazing Interruption System Working!");return;}
Все это прекрасно работает.
Но ........ можно ли использовать cancel / cancelAllOperations / .isCanlled с этим типом использования GCD?
Что здесь за история?Приветствия.
PS - для любых новичков, использующих этот фоновый шаблон «из шести частей».
Обратите внимание, что, как подчеркивает BJ ниже, всякий раз, когда вы выходите из процесса bg ...
Вы должны очистить все открытые переменные!
В моем идиоме вы должны выделить все переменные, контексты, память и т. Д., В частности, в "setUpHere".И вы должны выпустить их в "wrapUpHere".(Эта идиома продолжает работать, если вы идете все глубже и глубже, находясь в BG.)
Поочередно, делайте именно то, что BJ показывает в своем примере.(Если вы используете метод BJ, будьте осторожны, если вы пойдете глубже.)
Какой бы метод вы ни использовали, вы должны очистить все переменные / контексты / память, которые вы открыли, когда выйдете из процесса BG.Надеюсь, это когда-нибудь кому-нибудь поможет!