UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Project 2: Guess the Flag - Problem with adding a second alert

Forums > 100 Days of SwiftUI

I have been adding additional functionality to the base app from the tutorial. I am trying to make a button that will restart the game. I made the button ok but I can't get the confirmation alert to work. I know the second alert has to be on a different view which I believe I have done. Any idea what I am doing wrong? (Also any comentary on how the rest of the code conforms to best practices would be appreciated. I am trying to develop good habits from the start.)

//
//  ContentView.swift
//  GuessTheFlag
//
//  Created by Sean McComas on 4/26/21.
//

import SwiftUI

struct ContentView: View {

    @State private var countries = ["Estonia", "France", "Germany", "Ireland", "Italy", "Nigeria", "Poland", "Russia", "Spain", "UK", "US"].shuffled()
    @State private var correctAnswer = Int.random(in: 0...2)

    @State private var showingScore = false
    @State private var scoreTitle = ""
    @State private var alertMessage = ""
    @State private var scoreCounter = 0
    @State private var startOver = false

    var body: some View {
        ZStack {
            LinearGradient(gradient: Gradient(colors: [.blue, .black]), startPoint: .top, endPoint: .bottom)
                .edgesIgnoringSafeArea(/*@START_MENU_TOKEN@*/.all/*@END_MENU_TOKEN@*/)
            VStack(spacing: 30) {
                VStack {
                    Text("Tap the flag of")
                        .foregroundColor(.white)
                    Text(countries[correctAnswer])
                        .foregroundColor(.white)
                        .font(.largeTitle)
                        .fontWeight(.black)
                }
                ForEach(0 ..< 3) { number in
                    Button(action:{
                        self.flagTapped(number)
                    }) {
                        Image(self.countries[number])
                            .renderingMode(.original)
                            .clipShape(Capsule())
                            .overlay(Capsule().stroke(Color.black, lineWidth: 1))
                            .shadow(color: .black, radius: 2 )
                    }
                }
                VStack {
                    Text("Your score is")
                        .foregroundColor(.white)
                    Text(String(scoreCounter))
                        .foregroundColor(.white)
                        .font(.largeTitle)
                    Spacer()
                    Button(action:{
                        startOver = true
                    }) {
                        Text("Start Over")
                            .font(.title)
                            .padding(.horizontal)
                            .foregroundColor(.white)
                            .overlay(Capsule().stroke(Color.white, lineWidth: 1))
                    }
                    .alert(isPresented: $startOver) {
                        Alert(
                            title: Text("Start Over?"),
                            message: Text("Would you like to restart the game?"),
                            primaryButton: .destructive(Text("Yes")) {
                                scoreCounter = 0
                                startOver = false
                            },
                            secondaryButton: .default(Text("No")) {
                                startOver = false
                            }
                            )
                    }

                }

            }
            .alert(isPresented: $showingScore) {
                Alert(title: Text(scoreTitle), message: Text(alertMessage), dismissButton: .default(Text("Continue")) {
                    self.askQuestion()
                })
            }
            /*

            */
        }
    }

    func flagTapped(_ number:Int) {
        if number == correctAnswer {
            scoreTitle = "Correct"
            scoreCounter += 1
            alertMessage = "Your Score is \(scoreCounter)"
        } else {
            scoreTitle = "Wrong"
            alertMessage = "That is the flag of \(countries[number])"
        }

        showingScore = true
    }

    func askQuestion() {
        countries.shuffle()
        correctAnswer = Int.random(in: 0...2)
    }

}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

3      

Attach the showingScore alert higher up in the View hierarchy. For instance:

                VStack {
                    Text("Tap the flag of")
                        .foregroundColor(.white)
                    Text(countries[correctAnswer])
                        .foregroundColor(.white)
                        .font(.largeTitle)
                        .fontWeight(.black)
                }
                // <-- here
                ForEach(0 ..< 3) { number in
                    Button(action:{
                        self.flagTapped(number)
                    }) {
                        Image(self.countries[number])
                            .renderingMode(.original)
                            .clipShape(Capsule())
                            .overlay(Capsule().stroke(Color.black, lineWidth: 1))
                            .shadow(color: .black, radius: 2 )
                    }
                }
                // <-- or here

2      

Hi Sean

I agree with roosterboy on replacing of the Alert. However the "Restart" alert. You should not use Yes and No, and not use .destructive you would be better doing .default(Text("Start")) or .default(Text("Restart")) and for the other use .cancel()

also it a good idea to remove the action into a separate function. so you should try this

Alert(
    title: Text("Start Over!"),
    message: Text("Would you like to play again?"),
    primaryButton: .default(Text("Restart"), action: restart),
    secondaryButton: .cancel()
)

and function

func restart() {
    // here put to restart game
}

PS you do not need to change the showingScore booleen as this is done by the system when tap one of buttons

Link to Apple - Human Interface Guidelines on Alerts

2      

Thanks to both of you for the help. One additional question: Why did the showingScore alert need to be moved up?

2      

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

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

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

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.