I have just started working on iOS and have been going through Apple Reference material on GCD. dispatch_get_global _queue returns a concurrent queue to which one can submit a block to be executed.
However, we can achieve the same using dispatch_get_main_queue as well, right? Then, what exactly is the difference between dispatch_get_global_queue and dispatch_get_main_queue?
The global queue is a background queue and executes its blocks on a non-main thread. The main queue executes its blocks on the main thread.
You should put background work that does not involve changes to the user interface on the global queue, but use the main queue when the blocks make changes to the user interface. A very common pattern, for example, is to execute a "work" block on the global queue, and to have the work block itself dispatch back to the main queue to update a progress indicator.
dispatch_get_main_queue - should be used when you want to manipulate UI elements.
(It gets a background queue that you can dispatch background tasks that are run asynchronously... it won't block your user interface)
dispatch_get_global_queue - Can be used for network calls/core data.
Related
I'm creating an application in objective C where I have two threads:
The main thread, which is woken up from sleep and is called into asynchronously by a module above it
The callback block(thread) whose execution is asynchronous and is dependent on an external module "M" sending a notification.
On my main thread, I want to wait for the callback to come in before I start doing my tasks. So, I tried using dispatch_group_enter and dispatch_group_wait(FOREVER) on the main thread while calling into dispatch_group_leave on the callback thread. This ensured that when the main thread is the first to execute, things happen as they are supposed to, i.e the main thread waits for the callback to come in and unblock it before performing its tasks.
However, I'm seeing a race condition where the callback block gets called first sometimes and is stuck on dispatch_group_leave (since at this point the main thread has not called into dispatch_group_enter.
Is there a different GCD construct I can use for this purpose?
The “main thread” is a thread which handles UI, system events, notifications, etc. We never block that thread. Blocking it results in a horrible UX where the app will appear to freeze and your app may even be terminated by the “watch dog” process, which kills apps that it thinks are frozen. In some cases, the app will deadlock.
So, if you really mean “main thread”, then the answer is that you would never “wait” on that thread (or otherwise block it). The pattern is to have your background thread do what it needs, and then dispatch model/UI updates back to the main thread with GCD (or submit your notification and let the main thread process it).
If you want a UX where the user is not allowed to interact with the UI while this background process is underway, you would present something in your UI that makes that clear. A common pattern is a dimming/blurring view that covers the whole view, often with a UIActivityIndicatorView (i.e., a spinner), and when the task dispatched to the background queue is done (or have the notification handler do that), you’d then remove that dimming/blurred view and the spinner and update the UI accordingly.
But you never block the main thread by waiting.
Completion handler closures are common in iOS development, such as dataTask(with:completionHandler:) in the URLSession class.
The UI engine is managed by the main thread, the API calls by URLSession are run under the background thread and must be dispatched to the main thread if a UI update is needed in the handler.
Question 1:
Do all completion handler closures from the iOS framework run in the background thread?
Question 1.1:
Do all escaping closures, for example, created by developers, run in the background thread?
Question2:
I've seen up to 8 threads in the iPhone X simulator. Which one is the main thread and which one is the background thread in ios? Do they have different priorities and computational power?
Keep in mind that you are really asking about queues and threading more than completion handlers and closures. Code of any type is executed on a queue (which consists of one or more threads). There is nothing special about completion handler closures in this regard.
Q1 - Most iOS SDK provided completion handlers are called on a background queue but don't make that assumption unless the documentation specifically states what queue it is called on. Even URLSession can be configured to run on a specific queue, including the main queue.
Q1.1 - Closures that you write are run on whatever queue you call them from. There is no magic that makes them run on a background queue.
Q2 - The first thread is always the only thread of the main queue. All other threads are from background queues. Each thread can have whatever priority is was given based on the properties of its queue.
You should review the Dispatch documentation for further details, especially DispatchQueue.
Which queue is the best to place firebase operations? Is it the background queue, the main queue, or does it depend on how heavy the operation is?
It sort of depends on how much work you're doing in Firebase.
You can start out doing everything on the main thread. If you notice your UI lagging, switch to a background queue, and wrap all of your UI calls in a Dispatch.async call to the main thread.
I understand that dispatch_async() runs something on a background thread, and dispatch_main() runs it on the main thread, so where does dispatch_sync() come in?
You don't generally want to use dispatch_main(). It's for things other than regular applications (system daemons and such). It is, in fact, guaranteed to break your program if you call it in a regular app.
dispatch_sync runs a block on a queue and waits for it to finish, dispatch_async runs a block on a queue and doesn't wait for it to finish.
Serial queues run one block at a time, in order. Concurrent queues run multiple blocks at a time, and therefore aren't necessarily in order.
(edit)
Perhaps when you said dispatch_main() you were thinking of dispatch_get_main_queue()?
dispatch_main() is not for running things on the main thread — it runs the GCD block dispatcher. In a normal app, you won't need or want to use it.
dispatch_sync() blocks the current thread until the block completes. This may or may not be the main thread.
If you want to run something on the main thread, you can use dispatch_get_main_queue() to get the main queue and use once of the normal dispatch methods to run a block there.
When a block added to a queue is executed, is it possible to find out the queue info (such as if it is main queue, concurrent queue, etc.) and which thread the queue lives in?
Even through it's deprecated in iOS6, you can still use dispatch_get_current_queue() for debugging purposes. Then you can get main queue with dispatch_get_main_queue() and global queues with dispatch_get_global_queue() and check which one of them is equal to your queue.
You shouldn't directly compare queues in GCD. Please see this answer: Is this the right way to compare two GCD Queues?
If you only need to check if you are on the main thread (for interacting with UIKit for example), then use [NSThread isMainThread] or dispatch_async(dispatch_get_main_queue(), ...).