I have the following alerts:
.alert(scoreTitle, isPresented: $showingScore) {
Button("Continue", action: askQuestion)
} message: {
Text("Your score is \(totalCorrectAnswers)")
}
.alert("Game Over", isPresented: $showingGameOver) {
Button("Play Again", action: resetGame)
} message: {
Text("Your total score was \(totalCorrectAnswers)")
}
Note how they are triggered by showingScore
and ShowingGameOver
The alerts come into play when the following event handler is called
func flagTapped(_ number: Int) {
if number == correctAnswer {
scoreTitle = "Correct!"
totalCorrectAnswers = 1
} else {
scoreTitle = "Wrong! That was the flag of \(countries[number])"
totalCorrectAnswers = 0
}
showingScore.toggle()
attempts = 1
if attempts == maxAttempts {
showingGameOver.toggle()
}
}
As you can see, first the answer is checked and depending if the answer is correct or false, a different message will be displayed in the first alert. If we hit the limit of attempts, another alert comes right after and resets the game.
The problem I had was that if the last attempt was incorrect, the alerts would show out of order. Initially, I did not have this line totalCorrectAnswers = 0
, but I guessed (correctly) it might be necessary in order to get the alerts to trigger in the right. My guess is that this was fixed because totalCorrectAnswers
is a state property and it triggers a refresh, but it doesn't really explain why this was needed.
CodePudding user response:
Using a tuple variable and a method that staggers the alerts is one approach.
You need the staggering because you can't present one alert above the other reliably such as getting the wrong answer and game over at the same time.
import SwiftUI
@available(iOS 15.0, *)
struct AlertSampleView: View {
//One variable controls the single alert
@State var alertVariable:(title:String,isPresented: Bool, actionTitle: String ,action: () -> Void,message: String) = ("",false,"OK",{},"")
//MARK: Sample variables based on provided code
@State var correctAnswer = 1
@State var totalCorrectAnswers = 1
@State var attempts = 1
@State var maxAttempts = 2
var body: some View {
Button("answer", action: {
//Mimic result
flagTapped(Int.random(in: 0...2))
})
//Single alert
.alert(alertVariable.title, isPresented: $alertVariable.isPresented, actions: {
Button(alertVariable.actionTitle, action: alertVariable.action)
}, message: {
Text(alertVariable.message)
})
}
func flagTapped(_ number: Int) {
if number == correctAnswer {
scheduleAlert(title: "Correct!")
totalCorrectAnswers = 1
attempts = 0
} else {
scheduleAlert(title: "Wrong! That was the flag of ...")
attempts = 1
}
if attempts == maxAttempts {
scheduleAlert(title: "Game Over")
}
}
//Staggers the presentation of the alerts
func scheduleAlert(title: String, count:Int = 0){
//Delay Alert if there is one on the screen
if alertVariable.isPresented{
//After 5 secondsish dismiss what is there
if count >= 25{
alertVariable.isPresented = false
}
//This delay leaves a little gap between alerts
DispatchQueue.main.asyncAfter(deadline: .now() 0.2) {
scheduleAlert(title: title, count: count 1)
}
}else{
alertVariable.title = title
alertVariable.isPresented = true
}
}
}
@available(iOS 15.0, *)
struct AlertSampleView_Previews: PreviewProvider {
static var previews: some View {
AlertSampleView()
}
}