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: