Decoupling Threading details in SwiftUI with the Decorator Pattern

Mar 29, 2023

In this article, we'll look at how the Decorator Pattern can help SwiftUI views become cleaner and more centered on their main purpose by removing threading details. Let's see how this works.

The Decorator Pattern is a structural design pattern that allows you to add new functionality to an object without changing its fundamental structure. It involves a set of decorator classes that wrap concrete components. Decorator classes mirror the type of the components they decorate (they have the same interface) but add or override behavior.

Let's create a simple example:

Create the view and use the fetchData function:

Notice the DispatchQueue used here, it is needed because DispatchQueue.main.async is used to ensure that the closure updating the data state property is executed on the main thread.

When fetchData completes, it calls the provided closure with the new data. The closure then updates the data property, which triggers a redraw of the Text view. Since SwiftUI views are updated and drawn on the main thread, any changes to the UI (like updating the data property) should be made from the main thread to avoid potential race conditions or UI inconsistencies.
But now The ContentView fetches data onAppear and updates its state, but the threading details are mixed with the view code. Here come the Decorator Pattern to the rescue

Let's define a decorator protocol first:

And create a decorator:

This decorator accepts a content closure and an onAppear closure. It ensures that the closure is executed on the main thread.
We can now apply our MainThreadDecorator to the Text view: