FACTS:
I have a method executing on a background thread :
[currentGame performSelectorInBackground:@selector(playOn:) withObject:self];
This method basically contains a while loop that keeps on executing until the user clicks on a Quit button:
-(void) playOn: (UIViewController*) thisViewController
{
while(!quitButtonPressed)
{
// this is my method's main loop
}
}
PROBLEM:
If the user clicks on Quit somewhere in the middle of the above loop
the rest of the loop would have to execute before it checks the BOOL once again and eventually stops. In order to prevent that from
happening and have the while-loop stop as soon as the user clicks on
Quit, I guess I could also add manyif(quitButtonPressed) break;
here and there in my while loop in order to semi-constantly check and “immediately” break away if needed. However, this doesn’t seem
very clever or practical from a design perspective given the size of
the above main while-loop and the fact that it contains many smaller
while-loops inside of it (the number ofif.. break;I would have to
add would be quite big and could make things quite complicated to
figure out..)
POSSIBLE SOLUTION (but is it the right one?) :
So I was thinking that the best way would be to stop/cancel the
background thread on which the above method’s while loop is executing,
instead of the while-loop itself, inside the method, the moment the
user clicks on QuitIs this, or something similar (i.e. a better suggestion), possible and
how exactly could I do this?
POSSIBLE IMPLEMENTATION OF ABOVE SOLUTION:
I could create this new method:
-(void)checkQuitButton
{
while(!quitButtonPressed)
{
//wait
}
if(quitButtonPressed)
{
// stop this thread-->[currentGame performSelectorInBackground:@selector(playOn:) withObject:self];
// this is the method I'm looking for
}
}
And then I could start executing the above and my previous main method concurrently on two separate background threads as follows:
[currentGame performSelectorInBackground:@selector(playOn:) withObject:self];
[currentGame performSelectorInBackground:@selector(checkQuitButton) withObject:nil];
While the game while-loop is being executed another while-loop is checking the QuitButton at the same time. But is there a method that I can actually call in order to cancel what was started here:
[currentGame performSelectorInBackground:@selector(playOn:) withObject:self];
?
The correct solution is to periodically check for a “stop” flag. Abruptly terminating a thread provides no opportunity to clean up resources. In short, you would leak memory terribly.
But the deeper issue is that you almost certainly should not have this kind of thread. It strongly suggests an incorrect design. In iOS, most background operations should take the form of focused operations, implemented either with
NSOperationor blocks with Grand Central Dispatch. You should very, very seldom need a long lived thread that is performing many different kinds of functions. Within your operation, it should be fairly straightforward where to put the “check for cancel” statements.There is also almost no case where you should use
performSelectorInBackground:. It is an incredibly dangerous method that gives you very little control. Instead, read the Concurrency Programming Guide for guidance on how to properly implement background operations. Pay special attention to the section “Migrating Away From Threads.”