Updated for Xcode 14.2
Swift tasks can have a priority attached to them, such as .high
or .background
, but the priority can also be nil
if no specific priority was assigned. This priority can be used by the system to determine which task should be executed next, but this isn’t guaranteed – think of it as a suggestion rather than a rule.
Creating a task with a priority look like this:
func fetchQuotes() async {
let downloadTask = Task(priority: .high) { () -> String in
let url = URL(string: "https://hws.dev/chapter.txt")!
let (data, _) = try await URLSession.shared.data(from: url)
return String(decoding: data, as: UTF8.self)
}
do {
let text = try await downloadTask.value
print(text)
} catch {
print(error.localizedDescription)
}
}
await fetchQuotes()
Download this as an Xcode project
Although you can directly assign a priority to a task when it’s created, if you don’t then Swift will follow three rules for deciding the priority automatically:
.userInitiated
.nil
priority.This means not specifying an exact priority is often a good idea because Swift will do The Right Thing.
However, like I said you can also specify an exact priority from one of the following:
.high
, which is synonymous with .userInitiated
. As the name implies, this should be used only for tasks that the user specifically started and is actively waiting for.medium
, and again as the name implies this is a great choice for most of your tasks that the user isn’t actively waiting for..low
, which is synonymous with .utility
. This is the best choice for anything long enough to require a progress bar to be displayed, such as copying files or importing data..background
, which is for any work the user can’t see, such as building a search index. This could in theory take hours to complete.Like I said, priority inheritance helps get us a sensible priority by default, particularly when creating tasks in response to a user interface action.
For example, we could build a simple SwiftUI app using a single task, and we don’t need to provide a specific priority –it will automatically run as high priority because it was started from our UI:
struct ContentView: View {
@State private var jokeText = ""
var body: some View {
VStack {
Text(jokeText)
Button("Fetch new joke", action: fetchJoke)
}
}
func fetchJoke() {
Task {
let url = URL(string: "https://icanhazdadjoke.com")!
var request = URLRequest(url: url)
request.setValue("Swift Concurrency by Example", forHTTPHeaderField: "User-Agent")
request.setValue("text/plain", forHTTPHeaderField: "Accept")
let (data, _) = try await URLSession.shared.data(for: request)
if let jokeString = String(data: data, encoding: .utf8) {
jokeText = jokeString
} else {
jokeText = "Load failed."
}
}
}
}
Download this as an Xcode project
Any task can query its current priority using Task.currentPriority
, but this works from anywhere – if it’s called in a function that is not currently part of a task, Swift will query the system for an answer or send back .medium
.
SAVE 50% To celebrate WWDC23, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.
Link copied to your pasteboard.