Effortless SwiftUI Concurrency: Task Modifier
When working with SwiftUI, we often need to execute asynchronous code before our view appears. To do this, we can use the .task(priority:_:)
modifier.
Here’s a simple example of how to use this modifier:
struct MyView: View {
var body: some View {
Text("Hello, world")
.task {
await fetch()
}
}
}
In this case, the .task
modifier is used, and within it, an asynchronous function fetch()
is called. Thanks to this modifier, there's no need to place the code inside a Task
. To illustrate this, let's see how we can do something similar without using the modifier:
struct MyView: View {
var body: some View {
Text("Hello, world")
.onAppear {
Task {
await fetch()
}
}
}
}
This code does virtually the same thing; however, there’s a fundamental difference. For example, if we navigate to another view and then return to the initial view, onAppear(perform:)
will run again, but the code inside the .task
modifier won't. Within .task
, any running task is automatically canceled when the view disappears, helping to avoid memory and processor waste.
Setting Priority
When using .task
, we can specify the priority that the code will have so the system can determine when to execute it.
To indicate the priority, we can do the following:
.task(priority: .utility) {
await fetch()
}
In this case, we use the utility
priority.
Using id
to Trigger the Task
Another very useful parameter we can use is id
. With this, we can specify that we want the code inside the .task
modifier to execute whenever the value of a variable changes.
struct MyView: View {
@State var runTask: Bool = false
var body: some View {
Text("Hello, world")
.task(id: runTask) {
await fetch()
}
}
}
With this code, every time runTask
changes its value, the code inside the .task
modifier will be executed. Keep in mind that, to use the variable, it must conform to the Equatable
.
If you want to read the Spanish version of this article, you can find it here: https://asynclearn.com/blog/modificador-task/