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.
Related
I encountered a problem with non-iOS developer while describing the flow of OperationQueue. We already know that with OperationQueue we can start as many threads as we want to execute the tasks in sync/async way.
But in practical, some of the people want proof for the OperationQueue is getting executed in the background and not with UI(Main) thread.
I just want to demonstrate that when operation queue starts, it already starts its execution in the background.
I already have convinced that when we try to set qos for the operationQueue that we create, it has all the parameters of global queue's qos viz: default userInitiated userInteractive background and utility.
So that is already perfect example in code to prove that all the OperationQueue operations mentioned are run on global thread. Unless we declare the OperationQueue.main
As Shadowrun said, you can add assertions for Thread.isMainThread. Also, if you ever want to add test that you are not on the main queue, you can add a precondition:
dispatchPrecondition(.notOnQueue(.main))
But it should be noted that the whole purpose of creating an operation queue is to get things off the main thread. E.g., the old Concurrency Programming Guide: Operation Queues says [emphasis added]:
Operations are designed to help you improve the level of concurrency in your application. Operations are also a good way to organize and encapsulate your application’s behavior into simple discrete chunks. Instead of running some bit of code on your application’s main thread, you can submit one or more operation objects to a queue and let the corresponding work be performed asynchronously on one or more separate threads.
This is not to say that operation queues cannot contribute to main thread responsiveness problems. You can wait from the main thread for operations added to an operation queue (which is obviously a very bad idea). Or, if you neglect to set a reasonable maxConcurrentOperationCount and have thread explosion, that can introduce all sorts of unexpected behaviors. Or you can entangle the main thread with operation queues through a misuse of semaphores or dispatch groups.
But operations on an operation queue (other than OperationQueue.main) simply do not run on the main thread. Technically, you could get yourself in trouble if you started messing with the target queue of the underlying queue, but I can’t possibly imagine that you are doing that. If you are having main thread problems, your problem undoubtedly rests elsewhere.
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.
How to stop/cancel/suspend/resume tasks on GCD queue
How does one stop background queue operations? I want to stop some screens in our app. And some screens it should be auto resume. So, how does one pass a queue in iOS?
I mean when user have browsing the app time we run the background thread in dispatch_queue_t. But it never stops and resume in the code. So how does one suspend and resume a queue
To suspend a dispatch queue, it is simply queue.suspend() (dispatch_suspend(queue) in Objective-C). That doesn't affect any tasks currently running, but merely prevents new tasks from starting on that queue. Also, you obviously only suspend queues that you created (not global queues, not main queue).
To resume a dispatch queue, it is queue.resume() (or dispatch_resume(queue) in Objective-C). There's no concept of “auto resume”, so you'd just have to manually resume it when appropriate.
To pass a dispatch queue around, you simply pass the DispatchQueue object that you created (or the dispatch_queue_t object that you created when you called dispatch_queue_create() in Objective-C).
In terms of canceling tasks queued on dispatch queues, this is a was introduced in iOS 8. One can item.cancel() a DispatchWorkItem (dispatch_block_cancel(block) a dispatch_block_t object in Objective-C). This cancels queued blocks/items that have not started, but does not stop ones that are underway. If you want to be able to interrupt a dispatched block/item, you have to periodically examine item.isCancelled (or dispatch_block_testcancel() in Objective-C).
See https://stackoverflow.com/a/38372384/1271826 for examples on canceling dispatch work items.
If you want to cancel tasks, you might also consider using operation queues, i.e. OperationQueue (NSOperationQueue in Objective-C). Its cancelable operations have been around for a while and you're likely to find lots of examples online. It also supports constraining the degree of concurrency with maxConcurrentOperationCount (whereas with dispatch queues you can only choose between serial and concurrent, and controlling concurrency more than that requires a tiny bit of effort on your part).
If using operation queues, you suspend and resume by changing the suspended property of the queue. And to pass it around, you just pass the NSOperationQueue object you instantiated.
Having said all of that, I'd suggest you expand your question to elaborate what sort of tasks are running in the background and articulate why you want to suspend them. There might be better approaches than suspending the background queue.
In your comments, you mention that you were using NSTimer, a.k.a. Timer in Swift. If you want to stop a timer, call timer.invalidate() to stop it. Create a new NSTimer when you want to start it again.
Or if the timer is really running on a background thread, GCD “dispatch source timers” do this far more gracefully. With a GCD timer, you can suspend/resume it just like you suspend/resume a queue, just using the timer object instead of the queue object.
You can't pause / cancel when using a GCD queue. If you need that functionality (and in a lot of general cases even if you don't) you should be using the higher level API - NSOperationQueue. This is built on top of GCD but it gives you the ability to control how many things are executing at the same time, suspend processing of the queue and to cancel individual / all operations.
I am using Grand Central Dispatch to run a process in background. I want know how can i suspend, resume and stop that background thread. I have tried
dispatch_suspend(background_thread);
dispatch_resume(background_thread);
but these functions doesn't help me, it keeps on running. Please someone help me.
You seem to have some confusion. Direct manipulation of threads is not part of the GCD API. The GCD object you normally manipulate is a queue, not a thread. You put blocks in a queue, and GCD runs those blocks on any thread it wants.1
Furthermore, the dispatch_suspend man page says this:
The dispatch framework always checks the suspension status before executing a block, but such changes never affect a block during execution (non-preemptive).
In other words, GCD will not suspend a queue while the queue is running a block. It will only suspend a queue while the queue is in between blocks.
I'm not aware of any public API that lets you stop a thread without cooperation from the function running on that thread (for example by setting a flag that is checked periodically on that thread).
If possible, you should break up your long-running computation so that you can work on it incrementally in a succession of blocks. Then you can suspend the queue that runs those blocks.
Footnote 1. Except the main queue. If you put a block on the main queue, GCD will only run that block on the main thread.
You are describing a concurrent processing model, where different processes can be suspended and resumed. This is often achieved using threads, or in some cases coroutines.
GCD uses a different model, one of partially ordered blocks where each block is sequentially executed without pre-emption, suspension or resumption directly supported.
GCD semaphores do exist, and may suit your needs, however creating general cooperating concurrent threads with them is not the goal of GCD. Otherwise look at a thread based solution using NSThread or even Posix threads.
Take a look at Apple's Migrating Away from Threads to see if your model is suited to migration to GCD, but not all models are.
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.