FREE TRIAL: Accelerate your app development career with Hacking with Swift+! >>

How to run an asynchronous task when a view is shown

Paul Hudson    @twostraws   

Updated for Xcode 13.0

New in iOS 15

SwiftUI’s task() modifier is a more powerful version of onAppear(), allowing us to start asynchronous work as soon as the view is shown. Even better, the task will automatically be cancelled when the view is destroyed, if it has not already finished.

As the task is executed asynchronously, this is a great place to fetch some initial network data for your view. For example, if we wanted to fetch a list of messages from a server, decode it into an array of Message structs, then show it in a list, we might write something like this:

struct Message: Decodable, Identifiable {
    let id: Int
    let from: String
    let text: String
}

struct ContentView: View {
    @State private var messages = [Message]()

    var body: some View {
        NavigationView {
            List(messages) { message in
                VStack(alignment: .leading) {
                    Text(message.from)
                        .font(.headline)
                    Text(message.text)
                }
            }
            .navigationTitle("Inbox")
        }
        .task {
            do {
                let url = URL(string: "https://www.hackingwithswift.com/samples/messages.json")!
                let (data, _) = try await URLSession.shared.data(from: url)
                messages = try JSONDecoder().decode([Message].self, from: data)
            } catch {
                messages = []
            }
        }
    }
}

Download this as an Xcode project

The word “Inbox” in bold above a list of messages.

You can attach the task() modifier to any view in your hierarchy, even ones that are presented as a result of a navigation push – it will only actually start its work when the view is displayed.

To demonstrate this, we could create a simple website source code viewer where users had a choice of sites to check:

struct ContentView: View {
    let sites = ["Apple.com", "HackingWithSwift.com", "Swift.org"]

    var body: some View {
        NavigationView {
            List(sites, id: \.self) { site in
                NavigationLink(site) {
                    SourceViewer(site: site)
                }
            }
            .navigationTitle("View Source")
        }
    }
}

struct SourceViewer: View {
    let site: String
    @State private var sourceCode = "Loading…"

    var body: some View {
        ScrollView {
            Text(sourceCode)
                .font(.system(.body, design: .monospaced))
        }
        .task {
            guard let url = URL(string: "https://\(site)") else {
                return
            }

            do {
                let (data, _) = try await URLSession.shared.data(from: url)
                sourceCode = String(decoding: data, as: UTF8.self).trimmingCharacters(in: .whitespacesAndNewlines)
            } catch {
                sourceCode = "Failed to fetch site."
            }
        }
    }
}

Download this as an Xcode project

Both task() and onAppear() are able to run synchronous functions when you view is shown, so there’s no particular reason to choose one or the other beyond personal taste – there’s a nice balance to having both onAppear() and onDisappear() together.

Tip: By default, Swift tasks created using the task() modifier will run at the highest available priority, but you can pass a custom priority into the modifier if you know the work is less important.

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for iOS devs who want to become complete senior developers — from October 18th to 24th. Learn how to apply iOS app architecture patterns through a series of lectures and practical coding sessions.

Learn more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Similar solutions…

BUY OUR BOOKS
Buy Pro Swift Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift (Vapor Edition) Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Server-Side Swift (Kitura Edition) Buy Beyond Code

Was this page useful? Let us know!

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.