BLACK FRIDAY SALE: Save big on all my Swift books and bundles! >>

Alerts not working together

Forums > 100 Days of SwiftUI

Hi, the second alert works if the first is commented out but I cannot get them to work together. When showingScore is true and playAgain is true I expected the alerts to run one after the other but that is not the case.

I've added some extra Text fields to my view so I can watch the two variables and they are changing from false to true as I would expect. showingScore is reset to false by the alert and even though playAgain is true the alert does not appear.

    .alert(scoreTitle, isPresented: $showingScore) {
        Button("Continue", action: askQuestion)
    } message: {
        Text("Your score is \(usersScore) From \(guessesCounter) \(guessOrGuesses)")
    }

    .alert(isPresented: $playAgain) {
        Alert(title: Text("New Message"), primaryButton: .default(Text("Try Again"), action: resetGame), secondaryButton: .destructive(Text("Quit"), action: quitgame))
    }

Any help appreciated.

Regards

   

@iwaddo - just attach the second alert to some other View, its an issue where two simultaneous alerts do not respond ... good luck

   

or have one alert displaying different information depending on what happened...

   

hi,

the placement of .alert() modifiers makes a lot of difference. i think this post by Sarun provides an explanation for presenting multiple alerts in the most common situations.

if you need something more involved, you could look into using .alert(_:isPresented:presenting:actions:), where you can set up a single alert modifier on an entire view, but trigger it for different scenarios by defining an appropriate value for the presenting parameter. (this is along the lines of what what @GakkieNL is suggesting.)

something like this is fairly generic:

.alert(alertData.title, isPresented: $isAlertShowing, presenting: alertData) {
    item in item.actionsView()
} message: {
    item in item.messageView()
}

where the definition of alertData is

@State private var alertData = AlertData()

and AlertData is a base-level class defined with a default title (String), an actionsView (AnyView), and a messageView (AnyView).

Added after original reply: the AlertData class must be Identifiable.

any time you want to present an alert, you follow this sequence:

alertData = YourSpecialAlertDataType(/* initialization parameters here */) 
isAlertShowing = true

where YourSpecialAlertDataType is a subclass of AlertData and its initialization parameters are enough to determine the title, messageView, and actionsView needed for the alert.

however, that may be a little bit more than what you need.

hope that helps,

DMG

1      

Thank you, this is exactly what I need, different scenarios from a single alert modifier.

I need a message and continue when showingScore is true and a different message with different buttons and actions when playAgain is true.

I will give it a try.

Thank you for your help

   

There is also this way. By have one alert and passing in the error title and details depending on the error you want to show.

struct ContentView: View {
    @State private var showAlert = false
    @State private var title = ""
    @State private var message = ""

    var body: some View {
        VStack {
            Button("Error One") {
                title = "Error One"
                message = "The is attached to the button one"
                showAlert = true
            }
            .buttonStyle(.bordered)

            Button("Error Two") {
                title = "Error Two"
                message = "The is attached to the button two"
                showAlert = true
            }
            .buttonStyle(.bordered)
        }
        .alert(title, isPresented: $showAlert) {

        } message: {
            Text(message)
        }

    }
}

   

Have by playing around with alerts and came up with this.

Add a struct That has all the alert details in

struct AlertItem: Identifiable {
    let id = UUID()
    var title: String
    var message: String

    static let alertOne = AlertItem(
        title: "Alert One",
        message: "This is Alert One Message")

    static let alertTwo = AlertItem(
        title: "Alert Two",
        message: "This is Alert Two Message")

    static let alertThree = AlertItem(
        title: "Alert Three",
        message: "This is Alert Three Message")
}

Then when you want to call the alert have one Bool to trigger the alert and a optional alertItem so you can then say which alert to show

struct ContentView: View {
    @State private var showAlert = false
    @State private var alertItem: AlertItem?

    var body: some View {
        VStack {
            Button("Alert One") {
                alertItem = .alertOne // <- type of alert to show
                showAlert = true
            }

            Button("Alert Two") {
                alertItem = .alertTwo
                showAlert = true
            }

            Button("Alert Three") {
                alertItem = .alertThree
                showAlert = true
            }
        }
        .buttonStyle(.bordered)
        .padding()
        .alert(
            alertItem?.title ?? "", // <- unwrap optional "" will never show
            isPresented: $showAlert,
            presenting: alertItem)
        { _ in // Add buttons (no button will still use "Ok" button)
            Button("Understood") { }
        } message: { alertItem in
            Text(alertItem.message)
        }
    }
}

The advange of this is all alert detail are in one place and less in the Views

1      

Some hidden gems here, very informative indeed, this post is to be bookmarked .. thanks @NigelGee and @delawaremathguy

   

Hacking with Swift is sponsored by RevenueCat

SPONSORED In-app subscriptions are a pain to implement, hard to test, and full of edge cases. RevenueCat makes it straightforward and reliable so you can get back to building your app. Oh, and it's free if your app makes less than $10k/mo.

Learn more

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

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.