Swift iOS : Serial Function Execution

I wish to create a function that runs 3 internal functions 1 after the 1 and repeat that process 3 times. The problem I am finding is that all 3 functions execute simultaneously.

Currently when I test the app it turns green and that is it. Where I would like it to turn red for 30 seconds, then green for 10, then repeat that process 3 times.

I would like to keep the process open so I may add conditions such as "Play a sound at 4 seconds in) and allow the overall times to changeable in the future.

CODE:

import UIKit


var timer = Timer()
var intCount = 0
var seconds = 0

let greenColor = UIColor(red: 0/255.0, green: 255/255.0, blue: 0/255.0, alpha: 1.0)
let redColor = UIColor(red: 255/255.0, green: 0/255.0, blue: 0/255.0, alpha: 1.0)

// Start Button
@IBAction func Start(_ sender: Any)
{
    repeat
    {
        performTimer()
        intCount += 1
    }while intCount < 2

    StartHide.isHidden = true
}

func performTimer()
{
    timer1() // Execute -> Finish
    timer2() // Execute -> Finish
}

func timer1()
{

    // Set Seconds
    seconds = 30
    // Colour for 30 Seconds 
    view.backgroundColor = redColor
    // Run Timer
    timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timerPage.counter), userInfo: nil, repeats: true)
}

func timer2()
{
    // Set Seconds
    seconds = 10
    // Colour for 10 Seconds 
    view.backgroundColor = greenColor
    // Run Timer
    timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timerPage.counter), userInfo: nil, repeats: true)
}

func counter()
{

    seconds -= 1

    if (seconds == 0)
    {
        timer.invalidate()
    }

}

Surely there is a simple way to stop functions running simultaneously?

1 answer

  • answered 2018-01-14 07:00 Sweeper

    The timers are running simultaneously (a better word is asynchronously) because of this:

    repeat
    {
        performTimer()
        intCount += 1
    }while intCount < 2
    

    and this:

    func performTimer()
    {
        timer1() // Execute -> Finish
        timer2() // Execute -> Finish
    }
    

    The call to timer1 will return as soon as the timer has been created, not when the timer counts down to 30 seconds. Same goes for timer2 and performTimer methods.

    So you are creating all these timers in a very short time and they all share a seconds variable. That's bad.

    To fix this, you should only create new times after the one running has finished.

    let count = 0
    let seconds = 0
    var currTimer: Timer!
    func start() {
        timer30s()
    }
    
    func timer30s() {
        seconds = 30
        currTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: selector(handleTimer30s), userInfo: nil, repeats: true)
    }
    
    func timer10s() {
        seconds = 10
        currTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: selector(handleTimer10s), userInfo: nil, repeats: true)
    }
    
    func handleTimer30s() {
        if seconds > 0 {
            seconds -= 1
            return
        }
        currTimer.invalidate()
        timer10s()
        view.backgroundColor = redColor
    }
    
    func handleTimer10s() {
        if seconds > 0 {
            seconds -= 1
            return
        }
        count += 1
        currTimer.invalidate()
        if count < 3 {
            timer30s()
        }
        view.backgroundColor = greenColor
    }