I have a scenario in my app, where I want to do some time consuming task which consists of some data processing as well as UI update, in a method. My method looks like this,
- (void)doCalculationsAndUpdateUIs { // DATA PROCESSING 1 // UI UPDATE 1 // DATA PROCESSING 2 // UI UPDATE 2 // DATA PROCESSING 3 // UI UPDATE 3 }
As it is time consuming I wanted to do the data processing on the background thread, using,
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^{
But as both data processing and UI updates are in the same method, I wanted to move only the UI updates in main thread using,
dispatch_async(dispatch_get_main_queue(), ^{
Finally my method looks like this,
- (void)doCalculationsAndUpdateUIs { // DATA PROCESSING 1 dispatch_async(dispatch_get_main_queue(), ^{ // UI UPDATE 1 }); /* I expect the control to come here after UI UPDATE 1 */ // DATA PROCESSING 2 dispatch_async(dispatch_get_main_queue(), ^{ // UI UPDATE 2 }); /* I expect the control to come here after UI UPDATE 2 */ // DATA PROCESSING 3 dispatch_async(dispatch_get_main_queue(), ^{ // UI UPDATE 3 }); }
Does this really work? Is this really a good practice? What is the best way to achieve this?
P.S. All these three operations are interrelated to each other.
EDIT: Sorry guys. I have missed a line in the above code. My actual code looks like this.
- (void)doCalculationsAndUpdateUIs { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // DATA PROCESSING 1 dispatch_async(dispatch_get_main_queue(), ^{ // UI UPDATE 1 }); /* I expect the control to come here after UI UPDATE 1 */ // DATA PROCESSING 2 dispatch_async(dispatch_get_main_queue(), ^{ // UI UPDATE 2 }); /* I expect the control to come here after UI UPDATE 2 */ // DATA PROCESSING 3 dispatch_async(dispatch_get_main_queue(), ^{ // UI UPDATE 3 }); }); }
Once again, I really apologize for the confusion.
No it doesn't wait and the way you are doing it in that sample is not good practice.
dispatch_async
is always asynchronous. It's just that you are enqueueing all the UI blocks to the same queue so the different blocks will run in sequence but parallel with your data processing code.
If you want the update to wait you can use dispatch_sync
instead.
// This will wait to finish dispatch_sync(dispatch_get_main_queue(), ^{ // Update the UI on the main thread. });
Another approach would be to nest enqueueing the block. I wouldn't recommend it for multiple levels though.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // Background work dispatch_async(dispatch_get_main_queue(), ^{ // Update UI dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // Background work dispatch_async(dispatch_get_main_queue(), ^{ // Update UI }); }); }); });
If you need the UI updated to wait then you should use the synchronous versions. It's quite okay to have a background thread wait for the main thread. UI updates should be very quick.
You have to put your main queue dispatching in the block that runs the computation. For example (here I create a dispatch queue and don't use a global one):
dispatch_queue_t queue = dispatch_queue_create("com.example.MyQueue", NULL); dispatch_async(queue, ^{ // Do some computation here. // Update UI after computation. dispatch_async(dispatch_get_main_queue(), ^{ // Update the UI on the main thread. }); });
Of course, if you create a queue don't forget to dispatch_release
if you're targeting an iOS version before 6.0.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With