Is DispatchQueue.global(qos: .userInteractive).async same as DispatchQueue.main.async

I was going through the tutorial : https://www.raywenderlich.com/148513/grand-central-dispatch-tutorial-swift-3-part-1

And came across the definition of QoS class User-interactive. Its mentioned there that this should run on main thread. So, my question is then what is the difference between the

DispatchQueue.global(qos: .userInteractive).async{} 

and

DispatchQueue.main.async{}

Thanks!!


Solution 1:

The "quality of service" definitions are described here:

https://developer.apple.com/library/content/documentation/Performance/Conceptual/EnergyGuide-iOS/PrioritizeWorkWithQoS.html

It looks like the "main" thread will have a QoS class of "User-interactive". However, just because a thread is created with a QoS of "User-interactive", does not mean that it is the "main" thread.

You can observe this in the Xcode debugger. Put a breakpoint inside the async block and look at the Debug Navigator active thread panel. When DispatchQueue.global(qos: .userInteractive).async{} is called from the main thread, it displays with a different name than the main thread.

In general, the main thread is considered the special thread where all view-related access should be performed. If something will consume any significant time, e.g. calling a web service, compressing a file, etc., you will want to run code in a separate queue, and when the process completes, return to the main queue where you update the user interface.

Note also that when using Xcode 9 with iOS 11, a warning will be emitted when a user-interface object is accessed from a non-main thread.

Solution 2:

These are not the same. They mean different things and you should use the one you mean. The main queue is userInteractive, but not every userInteractive queue is the main queue. This is discussed well by Apple in Building Responsive and Efficient Apps with GCD.

It is valid to have multiple queues running at the userInteractive level. This is appropriate if you need to make use of multiple cores simultaneously to perform computations that are required in order to maintain a smooth user interaction (usually some kind of animation). This is very rare to need, and should be done with care, but if you need to compute something on the main thread while also computing something on another core in order to keep up with user actions, that's what it's there for.

But there can be only one main queue. It happens to be userInteractive, but that's not its point. Most of UIKit is not thread safe and it is only valid to access those classes on the main queue, not just any userInteractive queue.

Queue priorities are more complex they appear at first. They can propagate from queue to queue, such that "low priority" queues may temporarily have high priority status. Apple tweaks how this works a lot to make the whole system more responsive. This is why it's so important to always express what you mean rather than relying on assumptions about how things might work under the covers. Even if your tests show you that two queues are always the same, that wouldn't be enough to know that they will be the same on all devices or for future versions of the OS.

Solution 3:

Anyone who says the .userInitiated global queue is the main thread is just wrong. It's a very high priority background queue, but it is a background queue (and it is concurrent, unlike the main thread).

Apple's own sample code and comments make the matter quite clear:

// This handler gets called on the main thread; dispatch to a background queue for processing.
DispatchQueue.global(qos: .userInitiated).async {

This proves beyond a shadow of a doubt that Apple believes the .userInitiated global queue is a "background queue" and not the "main thread".