Delay Between Functions, but before a function

Hi, I need help. I’ve been looking for an answer for days, and this community has answered my questions best.

In the picture is the overall logic that I want to recreate.

Right now I’m struggling with two major points, the loop and the delay, but I’d like to focus on the former first, as it seems like a simpler problem to solve.

(I have a feeling the solution to the delay problem will have to involve custom classes or something)

If I create an infinite loop, how can I make the end condition to be the the tapping of a button?

I don’t think a loop is the best way to handle something like this.

Instead, something like this would, I think, be better:

(Note: This assumes a view with a single UIButton for both starting and stopping the timer.)

import UIKit

class ViewController: UIViewController {

    @IBOutlet var button: UIButton!
    
    var timer = Timer()
    var delay = 0.0
    var inLoop = false
    
    var loopCounter = 0
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func buttonTapped(_ sender: UIButton) {
        if inLoop {
            inLoop = false
            stopTimer()
        } else {
            inLoop = true
            startTimer()
        }
    }
    
    @objc func setDelay(currentTimer: Timer) {
        currentTimer.invalidate()
        delay = Double.random(in: 0...5)
        print("\(loopCounter) : \(delay)")
        timer = Timer.scheduledTimer(timeInterval: delay, target: self, selector: #selector(setDelay(currentTimer:)), userInfo: nil, repeats: true)
        loopCounter += 1
    }
    
    func startTimer() {
        print("timer started")
        setDelay(currentTimer: timer)
        button.setTitle("Stop Timer", for: .normal)
    }
    
    func stopTimer() {
        timer.invalidate()
        print("timer stopped")
        button.setTitle("Start Timer", for: .normal)
        delay = 0.0
        loopCounter = 0
    }
    
}

So in case this isn’t clear, what we’re doing is when the UI’s button is clicked we schedule a Timer object and set its timeInterval property to random Double values. (The initial timeInterval is 0, which means the timer will fire right away.) When the timer fires off, we invalidate it and create a new one with a new timeInterval value and do it all over again.

This will continue until you tap the button again to make it stop.

Make sense?

1 Like

thank you. I think this really puts me on the right tracks.

This looks like this loop is based upon the current function being used and is applied before the function.

What I’d like to do is call the function, and then cause a delay AFTER the function based on the Double value returned within it. clear as mud?

For example.

Random function one is called and returns:

“Turn to heading 180 degrees”

where the var currentHeading = 0

delay applied to the NEXT function would be (180 - currentHeading) / 3 + Double.random(1…15)

Random function two is now called, with the above delay.

the delay would be different depending on which function was previously called

Over and over again until button is tapped again to stop it.

Yep, that’s what this does.

Except that I realize in making an edit to the code I accidentally erased a comment that explained how to adapt it for your needs.

Where I have this line:

delay = Double.random(in: 0...5)

You should replace it with a call to a function that returns a Double, like:

delay = runRandomFunction()

And then runRandomFunction() would take care of getting a random function, running it and returning a Double value for the new delay amount.

Or if you wanted to do it all inline and you had a property called, say, funcArray that contained your list of functions that return a Double, you could do something like:

delay = funcArray.randomElement()!()

thanks! I’m going to try and make it work from all the stuff you’ve given me, it’s amazing. Are you okay if I message you again in case I get stuck?