RunLoop.main vs DispatchQueue.main: The differences explained

RunLoop.main vs DispatchQueue.main: The differences explained

In this post we will give you information about RunLoop.main vs DispatchQueue.main: The differences explained. Hear we will give you detail about RunLoop.main vs DispatchQueue.main: The differences explainedAnd how to use it also give you demo for it if it is necessary.

RunLoop.main and DispatchQueue.main are often used as schedulers within Combine. During code reviews, I often encounter inconsistency in using one or another, which made me realize it’s not always clear what the differences are. You might be surprised by the outcome of this article!

While you can use both RunLoop.main and DispatchQueue.main in different scenarios, I will focus on its usage within Combine for this article. You can assume that the same explanation applies to methods without using Combine.

Architecting SwiftUI apps with MVC and MVVMAlthough you can create an app simply by throwing some code together, without best practices and a robust architecture, you’ll soon end up with unmanageable spaghetti code. Learn how to create solid and maintainable apps with fewer bugs using this free guide.

What is a Combine scheduler?

A Combine scheduler defines when and how to execute a closure. Schedulers conform to the Scheduler protocol to which both RunLoop.main and DispatchQueue.main conform.

The most common example is using receive(on:options:) when setting up a Combine stream:

URLSession.shared
    .dataTaskPublisher(for: URL(string: "https://picsum.photos/300/600")!)
    .map(.data)
    .compactMap(UIImage.init)

    /// Schedule to receive the sink closure on the
    /// main dispatch queue.
    .receive(on: DispatchQueue.main, options: nil)
    
    .sink { _ in
        print("Image loading completed")
    } receiveValue: { image in
        self.image = image
    }.store(in: &cancellables)

As you can see in the above code example, we’re making sure to receive the image on the main thread using the DispatchQueue.main scheduler. The main queue scheduler is required since we need to perform UI updates on the main thread.

What is RunLoop.main?

A RunLoop is a programmatic interface to objects that manage input sources, such as touches for an application. A RunLoop is created and managed by the system, who’s also responsible for creating a RunLoop object for each thread object. The system is also responsible for creating the main run loop representing the main thread.

What is DispatchQueue.main?

DispatchQueue.main is the dispatch queue associated with the main thread of the current process. The system is responsible for generating this queue which represents the main thread. A dispatch queue executes tasks serially or concurrently on its associated thread.

If you want to read more about dispatch queues, I encourage you to read my article Concurrent vs Serial DispatchQueue: Concurrency in Swift explained.

RunLoop.main and DispatchQueue.main are the same but different

Both RunLoop.main and DispatchQueue.main execute their code on the main thread, meaning that you can use both for updating the user interface. Both schedulers allow us to update the UI after a Combine value was published, which is why there’s no apparent reason stopping us from using one or another. Though, there are some essential differences to know.

The differences between RunLoop.main and DispatchQueue.main

The most significant difference between RunLoop.main and DispatchQueue.main is that the latter executes directly while the RunLoop might be busy. For example, presenting a downloaded image while scrolling will only immediately show when using the DispatchQueue.main as a scheduler:

As you can see in the above recording, the image is only updated after scrolling when using RunLoop.main:

URLSession.shared
    .dataTaskPublisher(for: URL(string: "https://picsum.photos/300/600")!)
    .map(.data)
    .compactMap(UIImage.init)

    /// Scheduling using RunLoop.main delays closure
    /// execution until scrolling stops.
    .receive(on: RunLoop.main, options: nil)

    .sink { _ in
        print("Image loading completed")
    } receiveValue: { image in
        self.image = image
    }.store(in: &cancellables)

In other words: the execution of closures scheduled on the main run loop will be delayed for execution whenever user interaction occurs.

Understanding the behaviour of the main RunLoop

To better understand why the above image is not updating during scrolling, it’s good to understand what’s happening when you start scrolling. The RunLoop.main uses several modes and switches to a non-default mode when user interaction occurs. However, RunLoop.main as a Combine scheduler only executes when the default mode is active. In other words, the mode is switched back to default when user interaction ends and the Combine closure executes.

So, should I ever use RunLoop.main?

My advice would be to use the DispatchQueue.main by default as a Combine scheduler when you want to update the user interface. It’s unlikely that you want to wait for user interaction to end before processing new updates to your views.

However, updating your UI while scrolling might affect the frames per second (FPS) and smooth scrolling. It could be that your UI update isn’t as necessary when the user is scrolling. In that case, it might make sense to opt-in to using RunLoop.main as a scheduler.

Architecting SwiftUI apps with MVC and MVVMAlthough you can create an app simply by throwing some code together, without best practices and a robust architecture, you’ll soon end up with unmanageable spaghetti code. Learn how to create solid and maintainable apps with fewer bugs using this free guide.

Conclusion

RunLoop.main and DispatchQueue.main have much in common but come with a significant difference that can lead to unexpected behavior in our apps. Since both schedulers allow us to update the user interface, there’s no apparent reason to use one or another. Hopefully, after reading this article, you’re better aware of the differences and when to use which.

To read more about Swift Combine, take a look at my other Combine blog posts:

<!– Disable cross link to Medium



Also published on Medium.

–>

 

Hope this code and post will helped you for implement RunLoop.main vs DispatchQueue.main: The differences explained. if you need any help or any feedback give it in comment section or you have good idea about this post you can give it comment section. Your comment will help us for help you more and improve us. we will give you this type of more interesting post in featured also so, For more interesting post and code Keep reading our blogs

For More Info See :: laravel And github

We're accepting well-written guest posts and this is a great opportunity to collaborate : Contact US