How to ensure thread synchronization
-
17-06-2021 - |
Вопрос
I have a method myButtonAction
which performs some heavy calculations, which I need to run on a background thread, while I am loading a view indicating "Task progress" in the main thread. As soon as the, background thread completes executing the method, I need to remove the "task progress" view and load another view in the main thread.
[self performSelectorInBackground:@selector(myButtonAction) withObject:nil];
[self performSelectorOnMainThread:@selector(LoadView) withObject:nil waitUntilDone:YES];
The problem I am facing is that, before myButtonAction
completes execution, the LoadView
completes its execution. How can I make sure that LoadView
starts execution only after myButtonAction
completes its execution.
Note: myButtonAction
has its method definition in another class.
Решение
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self myButtonAction];
dispatch_async(dispatch_get_main_queue(), ^{
[self LoadView];
});
});
Or, if you want to stay with performSelector
methods:
[self performSelectorInBackground:@selector(loadViewAfterMyButtonAction) withObject:nil];
where
- (void)loadViewAfterMyButtonAction
{
[self myButtonAction];
[self performSelectorOnMainThread:@selector(LoadView) withObject:nil waitUntilDone:YES];
}
Другие советы
You need to do following -
[self performSelectorInBackground:@selector(myButtonAction) withObject:nil];
- (void)myButtonAction {
//Perform all the background task
//Now switch to main thread with all the updated data
[self performSelectorOnMainThread:@selector(LoadView) withObject:nil waitUntilDone:YES];
}
EDIT - Then you can try -
[self performSelectorInBackground:@selector(buttonActionInBackground) withObject:nil];
- (void)buttonActionInBackground {
[self myButtonAction];
//Now switch to main thread with all the updated data
[self performSelectorOnMainThread:@selector(LoadView) withObject:nil waitUntilDone:YES];
}
Now you don't need to change myButtonAction
.
I take it that this code gets called at the end of myButtonAction:
[self performSelectorOnMainThread:@selector(LoadView) withObject:nil waitUntilDone:YES];
now no wonder that LoadView finishes before myButtonAction finishes, because you said it to wait until it's done with "waitUntilDone:YES". Call it at the end with waitUntilDone:NO.
For simple solutions to this kind of problems take a look at putting selector calls into the main run loop using [self performSelector:@selector(sel) withObject:obj afterDelay:0.0]
or NSTimer - for example if you want to wait until UI updates are finished.
I use a Semaphore Design Pattern for these purposes.