Home Understanding SwiftUI View Lifecycle Methods
Post
Cancel

Understanding SwiftUI View Lifecycle Methods

When developing iOS apps, it’s common to need to perform certain actions or side effects in response to specific lifecycle events of a view, such as loading or refreshing data when a view appears. In UIKit, we used to accomplish this by overriding methods like viewDidAppear(:) or viewDidDisappear(:). With SwiftUI, we can use similar methods such as onAppear(perform:), onDisappear(perform:) and task(priority:_:) to react to these events. In this article, we’ll explore these methods in greater detail.

What is the view lifecycle?

The view lifecycle is a sequence of events that occur when a SwiftUI view is created, displayed, updated, and removed. SwiftUI provides a set of methods that allow us to respond to these events and perform custom actions, such as initializing state, updating views, and cleaning up resources. For better clarity we can organize the view lifecycle methods into three main categories:

  • Performing an action before the view Appears
  • Performing an action before the view Disappears
  • Refreshing the view when a specific value Changes

Performing an action before the view Appears

Since the SwiftUI framework does not use View Controllers like UIKit, firing an action right before a view appears is just a matter of attaching a onAppear(perform:) method to the specific view and what ever is in the onAppear(perform:) block will be called whenever the view appears. Take a look at an example code below:

1
2
3
4
5
VStack {
    Text("HEY just a Vertical Stack")
}.onAppear {
    print("VStack appeared!")
}

As you can see SwiftUI’s declarative way of binding the views to the underlying viewmodel with property wrappers, extends to lifecycle methods as well, since it makes it easy to determine which subviews are currently displayed.

Performing an async work before the view Appears

What if we need to kick start an asynchronious piece of work right before the view appears? Like let’s say we need to load our data before the view is visible, the sort of task we would delegate to a viewDidLoad method or perhaps viewWillAppear in UIKit. Well the task(priority:_:) method got us covered.

The task(priority:_:) method can be used to start some asynchronious work right before the view appears. Like they say a line of code is worth a thousand explanations, let’s see an example below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct SampleView: View {

    var body: some View {
        VStack {
           Text("HEY just a Vertical Stack")
        }
        .task {
            do {
                try await viewModel.fetchSomeDataFromAPI()
            } catch {
                ...
            }
        }
    }
}

Additionally, the task(priority:_:) will automatically cancels the task when the view disappears. Isn’t that sweet? an async block that cleans up after itself.

Performing an action before the view Disappears

As a counterpart to the onAppear(perform:) method, the onDisappear(perform:) method can be used to do some work right after the view disappears - for example to cancel running tasks.

1
2
3
4
5
6
VStack {
    Text("HEY just a Vertical Stack")
}.onDisappear {
    print("VStack Disappeared!")
    viewModel.cancelLoading()
}

For my UIKit devs, this is your SwiftUI’s equivalent of viewDidDisappear(:) you can throw your clean up tasks or any logic you need to fire right after the view disappears in here.

Refreshing the view when a specific value Changes

What if we want to refresh a view when a specific value in our data model changes? Well the onChange(of:perform:) view modifier got us covered. This method is called when a specific state variable we are subscribed to changes. You can use this method to update the view’s appearance or trigger other side effects. Let’s see it in action:

1
2
3
4
5
6
7
VStack {
    Text("HEY just a Vertical Stack")
}.onChange(of: vm.searchText) { newValue in
        if newValue == "" {
            dismissKeyboard()
        }
    }

In the example above let’s imagine we have a viewmodel with a published searchText property, and we want to know when our searchText is empty so we can dismiss keyboard, as you can see the onChange(of:perform:) method comes in clutch for us as a listener.

Reacting to application Lifecycle Events

Although not a SwiftUI view lifecycle method per se, the onReceive(_:perform:) method can be useful to react to application lifecycle events - for example to update a view when the app enters foreground.

The onReceive(_:perform:) method is similar to onChange(of:perform:) method we discussed above, but it is used to respond to changes in external data sources, such as notifications, publishers, or other general application events. Here’s an example:

1
2
3
4
5
6
7
8
9
10
11
struct ExampleView: View {
    var body: some View {
        VStack {
            ...
        }
        .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
            viewModel.update()
            print("app entering foreground now")
        }
    }
}

Summary

  • onAppear(): We use this method to perform any action when the view appears on screen, such as starting an animation or loading data from a remote source.

  • onDisappear(): We use this method to perform any action when the view disappears from screen, such as stopping an animation or releasing resources.

  • onChange(of:perform:): We use this method to perform any action when a specific variable we are subscribed to changes, such as updating the view’s appearance.

  • onReceive(_:perform:): We use this method to respond to various app lifecycle events, such as the application transitioning to the background state. This method can be leveraged to trigger specific actions, such as saving user data before the app enters the background.

By implementing the view lifecycle methods, we can customize the behavior of our views and respond to changes in their state. We can also use the view lifecycle methods to manage resources and ensure that our app runs efficiently and smoothly.

Conclusion

In conclusion, SwiftUI’s view lifecycle methods provide a powerful way to manage the lifecycle of our views and respond to changes in their state. By understanding the purpose of each method and how to use them, we can build more robust and responsive user interfaces for our iOS, macOS, watchOS, and tvOS applications.

This post is licensed under CC BY 4.0 by the author.