GO FURTHER, FASTER: Try the Swift Career Accelerator today! >>

SOLVED: SOLVED Day 34 -- how can I make the alert wait for the animations to finish?

Forums > 100 Days of SwiftUI

title says it all. Right now, the alert is covering up the animations I've so carefully crafted. How can I get the alert to wait a second before showing?

2      

Hey Now seeks advice for delaying code execution:

how can I make the alert wait for the animations to finish?

This hint might be useful?
See -> Rooster's Delay function

Wait?! Is it pronouced "Hey Now?" or "Hal No?"

3      

@Bnerd  

How I would approach:

  • Use a timer
  • Timer starts when your criteria for the alert is met
  • When timer reaches the time duration of your animation you trigger you boolean alert value
  • Stop/reset timer
  • Alert pops up

:) I am sure there is a more sophisticated way, but this what I thought for now..

3      

@Obelix -- thanks for the help. I take it the answer is, "Answer non-trivial, ask again later when we get to concurrency."

Originally I was @haineux, which is the French word for "Heinous" ("horrible and evil") for silly reasons. "Haineux" is pronounced "Hey No" in French.

2      

@ioannisfa Not quite figuring it out. Here's my code:

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 attempts = 0
    @State private var correct = 0
    @State private var selectedFlag = -1
    @State private var hasTimeElapsed = false

    var body: some View {
        ZStack {
            LinearGradient(gradient: Gradient(colors: [.blue, .gray]), startPoint: .top, endPoint: .bottom)
                .ignoresSafeArea()

            VStack(spacing: 30) {
                VStack {
                    Text("Tap the flag of")
                        .foregroundColor(.white)
                        .font(.subheadline.weight(.heavy))

                    Text(countries[correctAnswer])
                        .foregroundColor(.white)
                        .font(.largeTitle.weight(.semibold))

                }

                ForEach(0..<3) { number in
                    Button {
                        flagTapped(number)
                    } label: {
                        Image(countries[number])
                        }
                        .clipShape(RoundedRectangle(cornerRadius: 20))
                        .shadow(radius: 10, x:5, y:5)
                        .rotation3DEffect(.degrees(selectedFlag == number ? 360 : 0), axis: (x: 0, y: 1, z: 0))
                        .opacity(((selectedFlag == number) || (selectedFlag == -1))  ? 1 : 0.3)
                        .scaleEffect((selectedFlag == -1)  ? 1 : ((selectedFlag == number) ? 1.25 : 0.5))
                        .animation(.default, value: selectedFlag)
            }
        }
            .alert(scoreTitle, isPresented:$showingScore) {
                Button("Continue", action: askQuestion)
            } message: {
            Text("Your score is \(correct) out of \(attempts)")
            }
        }
    }

    func askQuestion() {
        countries.shuffle()
        correctAnswer = Int.random(in: 0...2)
        selectedFlag = -1
        hasTimeElapsed = false
 }

    func flagTapped(_ number: Int) {
        selectedFlag = number
        attempts += 1
        if number == correctAnswer {
            scoreTitle = "Correct"
            correct += 1
        } else {
            scoreTitle = "Wrong"
        }
        showingScore = true
    }

    private func delay() async {
        // Delay of 1 seconds (1 second = 1_000_000_000 nanoseconds)
        try? await Task.sleep(nanoseconds: 1_000_000_000)
        hasTimeElapsed = true
    }
}

3      

I like Rooster's delay function. When I did this challenge I used google to get the answer I used.

DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
        showingScore = true}

I don't know if it's the right way or best practice, but it worked for me.

4      

@WileECodee I like your solution a lot. I come from AppKit, so it's obvious in retrospect, ughhhhhh.

2      

Late to the show, but I wanted to do the same thing, and I ended up using the following code to make it work.

Update flagTapped(_ number: Int) method by replacing showingScore = true with

Task {
    try? await Task.sleep(nanoseconds: 1_000_000_000)
    await MainActor.run {
        showingScore = true
    }
}

I actually learned this today from the following article: Main Actor

Task will allow us to run the code in the background, sleep for x amount of seconds, then MainActor will ensure the next code runs on the UI thread.

3      

@daffyduck Thank you very many of this code snippet. I tried to found this kind of easy solution for delaying Alert. Have to check also that Main Actor infopage.

2      

Go further, faster with the Swift Career Accelerator.

GO FURTHER, FASTER Unleash your full potential as a Swift developer with the all-new Swift Career Accelerator: the most comprehensive, career-transforming learning resource ever created for iOS development. Whether you’re just starting out, looking to land your first job, or aiming to become a lead developer, this program offers everything you need to level up – from mastering Swift’s latest features to conquering interview questions and building robust portfolios.

Learn more here

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.