Search code examples
swiftdelay

Delay code in a function that is called multiple times per second


I'm building an app where I'm getting sensor values. Each time a sensor value changes, the function handleDeviceMotionUpdate is called, which is multiple times per second.

handleDeviceMotionUpdate calls the following function of a different class:

func doStuff(){
     delay(1){
           print("some thing")
     }
}

The delay function looks like this, which I found somewhere here on Stackoverflow:

func delay(_ delay:Double, closure:@escaping ()->()){
    let when = DispatchTime.now() + delay
    DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}

I expected that "some thing" is only printed after one second has passed, but I believe the problem is that doStuff() is called multiple times per second. Is there some way I can execute code after a certain delay in a function that is called multiple times per second? And why is my example not working?

I thought about creating a boolean variable in the first class that is set to true after 1 second and then calling the function of the different class, but I thought that might clutter my code because I've already done that somewhere else.


Solution

  • To do so declare a global timer:

    var timer: Timer = Timer(timeInterval: -1, target: self, selector: #selector(ViewControllerName.doStuff), userInfo: nil, repeats: false)
    

    Where ViewControllerName is the name of the class that has doStuff() as a method.

    Make sure to invalidate the timer initially (like in viewDidLoad()) :

    timer.invalidate()
    

    And here is how your doStuff() might look like:

    func doStuff() {
        //As long as the timer is started/vlaid, nothing will be executed
        if !timer.isValid {
            //print something or do whatever you'd like
            print("some thing ", Date()) 
    
            //and finally restart the timer
            timer = Timer.scheduledTimer(
                timeInterval: 1, //This is the time interval you don't want to do nothing
                target: self, 
                selector: #selector(ViewController.doStuff),
                userInfo: nil,
                repeats: false)
        }
    }