Post

Alert in SwiftUI

Alert in SwiftUI

There are several ways to present an alert in SwiftUI. Let’s go through them one by one.

1. Alert with title

SwiftUI will present an alert when a given condition is true, using a text view for the title.

The method definition is below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
nonisolated
func alert<A>(
    _ title: Text,
    isPresented: Binding<Bool>,
    @ViewBuilder actions: () -> A
) -> some View where A : View

nonisolated
func alert<A>(
    _ titleKey: LocalizedStringKey,
    isPresented: Binding<Bool>,
    @ViewBuilder actions: () -> A
) -> some View where A : View

nonisolated
func alert<S, A>(
    _ title: S,
    isPresented: Binding<Bool>,
    @ViewBuilder actions: () -> A
) -> some View where S : StringProtocol, A : View

This is a simplest form for an alert. Let’s see an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
struct LoginView: View {
    @EnvironmentObject var authStore: AuthStore

    @State private var username = ""
    @State private var password = ""
    @State private var showingErrorAlert = false

    var body: some View {
        VStack {
            // ...

            Button("Log in", action: login)
        }
        .alert("Login failed.", isPresented: $showingErrorAlert) {
            Button("OK", role: .cancel) { }
        }
    }

    private func login() {
        Task {
            do {
                try await authStore.login(username: username, password: password)
            } catch  {
                showingErrorAlert = true
            }
        }
    }
}

In the above example, SwiftUI will present an error alert when showingErrorAlert is true.

Alert

2. Alert with title and message

You can also present an alert with a message when a given condition is true.

The method definition is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
nonisolated
func alert<A, M>(
    _ title: Text,
    isPresented: Binding<Bool>,
    @ViewBuilder actions: () -> A,
    @ViewBuilder message: () -> M
) -> some View where A : View, M : View

nonisolated
func alert<A, M>(
    _ titleKey: LocalizedStringKey,
    isPresented: Binding<Bool>,
    @ViewBuilder actions: () -> A,
    @ViewBuilder message: () -> M
) -> some View where A : View, M : View

nonisolated
func alert<S, A, M>(
    _ title: S,
    isPresented: Binding<Bool>,
    @ViewBuilder actions: () -> A,
    @ViewBuilder message: () -> M
) -> some View where S : StringProtocol, A : View, M : View

A simple code example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
struct LoginView: View {
    @EnvironmentObject var authStore: AuthStore

    @State private var username = ""
    @State private var password = ""
    @State private var errorMessage = ""
    @State private var showingErrorAlert = false

    var body: some View {
        VStack {
            // ...

            Button("Log in", action: login)
        }
        .alert("Error", isPresented: $showingErrorAlert) {
            Button("OK", role: .cancel) {}
        } message: {
            Text(errorMessage)
        }
    }

    private func login() {
        Task {
            do {
                try await authStore.login(username: username, password: password)
            } catch  {
                errorMessage = error.localizedDescription
                showingErrorAlert = true
            }
        }
    }
}

SwiftUI will present an alert with message when showingErrorAlert is true.

Alert

3. Alert using data

We are able to present an alert using the given data to produce the alert’s actions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
nonisolated
func alert<A, T>(
    _ title: Text,
    isPresented: Binding<Bool>,
    presenting data: T?,
    @ViewBuilder actions: (T) -> A
) -> some View where A : View

nonisolated
func alert<A, T>(
    _ titleKey: LocalizedStringKey,
    isPresented: Binding<Bool>,
    presenting data: T?,
    @ViewBuilder actions: (T) -> A
) -> some View where A : View

nonisolated
func alert<S, A, T>(
    _ title: S,
    isPresented: Binding<Bool>,
    presenting data: T?,
    @ViewBuilder actions: (T) -> A
) -> some View where S : StringProtocol, A : View

For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
struct LoginView: View {
    @EnvironmentObject var authStore: AuthStore

    @State private var username: String = ""
    @State private var password: String = ""
    @State private var error: Error? = nil
    @State private var showingErrorAlert = false

    var body: some View {
        VStack {
            // ...

            Button("Log in", action: login)
        }
        .alert("Login failed.", isPresented: $showingErrorAlert, presenting: error) { error in
            if error.needRetry {
                Button("Retry") { // ... }
            }
            Button("OK", role: .cancel) {}
        }
    }

    private func login() {
        Task {
            do {
                try await authStore.login(username: username, password: password)
            } catch  {
                self.error = error
                showingErrorAlert = true
            }
        }
    }
}

SwiftUI will present the alert when showingErrorAlert is true and call actions ViewBuilder when error is not nil. After the alert is dismissed, the showingErrorAlert will be set to false, however, error will remain unchanged.

Alert

4. Alert with title and message using data

We are able to present an alert with title and message using the given data to produce the alert’s actions and message as well.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
nonisolated
func alert<A, M, T>(
    _ title: Text,
    isPresented: Binding<Bool>,
    presenting data: T?,
    @ViewBuilder actions: (T) -> A,
    @ViewBuilder message: (T) -> M
) -> some View where A : View, M : View

nonisolated
func alert<A, M, T>(
    _ titleKey: LocalizedStringKey,
    isPresented: Binding<Bool>,
    presenting data: T?,
    @ViewBuilder actions: (T) -> A,
    @ViewBuilder message: (T) -> M
) -> some View where A : View, M : View

nonisolated
func alert<S, A, M, T>(
    _ title: S,
    isPresented: Binding<Bool>,
    presenting data: T?,
    @ViewBuilder actions: (T) -> A,
    @ViewBuilder message: (T) -> M
) -> some View where S : StringProtocol, A : View, M : View

The code example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
struct LoginView: View {
    @EnvironmentObject var authStore: AuthStore

    @State private var username: String = ""
    @State private var password: String = ""
    @State private var error: Error? = nil
    @State private var showingErrorAlert = false

    var body: some View {
        VStack {
            // ...

            Button("Log in", action: login)
        }
        .alert("Error", isPresented: $showingErrorAlert, presenting: error) { error in
            if error.needRetry {
                Button("Retry") { // ... }
            }
            Button("OK", role: .cancel) {}
        } message: { error in 
            Text(error.localizedDescription)
        }
    }

    private func login() {
        Task {
            do {
                try await authStore.login(username: username, password: password)
            } catch  {
                self.error = error
                showingErrorAlert = true
            }
        }
    }
}
Alert

References

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