ViewDidLoad in SwiftUI

Hello. I want to do a fetch when a view loads. In UIKit I would have used viewDidLoad to do this but in SwiftUI we only have onAppear and task. Is that by design, and if so, what is the recommended way to fetch data?

I wrote a little blog post for a workaround describing the issue and the found solution, but I presume there is a better way. https://www.ludafux.com/post/viewdidload_doppelganger

Best Regards, Luda

Answered by DTS Engineer in 794471022

@fuxlud

task and onAppear have the same semantics for when they are executed which is before the first view is shown. However, task has a few more capabilities:

  • task(priority:_:) uses an async closure, making it more convenient for triggering asynchronous tasks without needing to use Swift's Task within onAppear and it provides additional parameters for fine-grained task management, such as configuring its priority and using its id to cancel and restart tasks if needed.

The UIKit viewDidAppear(:) and viewDidDisappear(:) methods are invoked specifically around when views become visible/not visible to the user, whereas the SwiftUI calls to onAppear or task are tied more to when the views are constructed/torn down, rather than visually presented.

I think both task and onAppear are executed before the view is displayed, so you can use either.

A quick internet search suggests this page has some good examples: https://byby.dev/swiftui-task-vs-onappear

@darkpaw the question is when is it called, but how many times it is called. both task and onAppear are called every time the view appears, like for example when the user navigated to another tab of the app and then comes back to it. viewDidLoad on the other hand was called only once. It can be achieved with a modifier holding a boolean to flag if the action ran already. But I am sure that the fact viewDidLoad is missing in SwiftUI is by design. And I would love to understand why is that.

@fuxlud

task and onAppear have the same semantics for when they are executed which is before the first view is shown. However, task has a few more capabilities:

  • task(priority:_:) uses an async closure, making it more convenient for triggering asynchronous tasks without needing to use Swift's Task within onAppear and it provides additional parameters for fine-grained task management, such as configuring its priority and using its id to cancel and restart tasks if needed.

The UIKit viewDidAppear(:) and viewDidDisappear(:) methods are invoked specifically around when views become visible/not visible to the user, whereas the SwiftUI calls to onAppear or task are tied more to when the views are constructed/torn down, rather than visually presented.

If you don't want to use .task as recommended by the Apple employee before me, then you might want to implement something like an .onFirstAppear so it's only executed once. Something like this should work:

private struct OnFirstAppear: ViewModifier {
    let perform: () -> Void

    @State private var firstTime = true

    func body(content: Content) -> some View {
        content.onAppear {
            if firstTime {
                firstTime = false
                perform()
            }
        }
    }
}

extension View {
    func onFirstAppear(perform: @escaping () -> Void) -> some View {
        modifier(OnFirstAppear(perform: perform))
    }
}

Use it as you would use .onAppear.

ViewDidLoad in SwiftUI
 
 
Q