1

Alright, so the problem I am encountering is that I can not stop this while loop midway using a button. For some reason, the button is un-pressable when the while loop is running. Context: trying to make an extremely basic metronome using Swiftui.

Here is all my code:

import SwiftUI
import AVFoundation

var player: AVAudioPlayer!

struct ContentView: View {
    @State var i = 0;
    func metronome() {
        while (i < 100) {
            i = i + 1
            sleep(1)
            playSound()
        }
        return
    }
    @State var bpm: Double = 0
    var body: some View {
        ZStack {
            Color.white
                .ignoresSafeArea()
            VStack(spacing: 100){
                
                //Makes it so that the icon is on top of button label
                VStack(spacing: 0){
                    
                    Image(systemName: "play.circle")
                        .foregroundColor(Color.green)
                        .font(.title)
                    Button{
                        i = 0
                        metronome()
                    } label: {
                        Text("Start").font(.largeTitle).bold()
                    }
                    .padding([.leading, .bottom, .trailing], 20.0)
                    .foregroundColor(Color.green)
                }
                
                VStack(spacing: 0){
                    
                    //Makes it so that the icon is on top of button label
                    Image(systemName: "pause.circle")
                        .foregroundColor(Color.red)
                        .font(.title)
                    
                    Button{
                        i = 101
                        metronome()
                    } label: {
                        Text("Stop").font(.largeTitle).bold()
                    }
                    .padding([.leading, .bottom, .trailing], 20.0)
                    .foregroundColor(Color.red)
                }
                .padding(.top, 20.0)
                
            }
        }
    }
    
    //function for playing sound effect
    func playSound() {
        let url = Bundle.main.url(forResource: "metronome", withExtension: "m4a")
        
        //Do nothing if this url is empty.
        guard url != nil else {
            return
        }
        
        do {
            player = try AVAudioPlayer(contentsOf: url!)
            player?.play()
        } catch{
            print("error")
        }
    }
}

Because my while loop only runs when i<100, I tried to set i=101 so the while loop will stop. However the problem I am encountering is that I can't even press the STOP button when the while loop is running.

Button{
    i = 101
    metronome()
}
burnsi
  • 6,194
  • 13
  • 17
  • 27
Metron
  • 25
  • 4
  • The sleep that you are doing here is sleeping the main thread. I’d suggest finding another way to play and pause your metronome. – Fogmeister Jun 11 '22 at 12:03
  • Do you have any suggestions for me on the top of your mind right now? – Metron Jun 11 '22 at 12:06
  • Use a repeating `Timer`. Then you can `invalidate` this timer when you want it to stop. And recreate timer when you want it to resume. – Rob Jun 11 '22 at 14:49
  • @Rob Could you show me how? I do not know what a Timer is in swiftui – Metron Jun 11 '22 at 15:00
  • Perhaps https://betterprogramming.pub/how-to-build-a-timer-using-swift-and-swiftui-e72cd8eb3d3a – Rob Jun 11 '22 at 16:27

0 Answers0