Do something every x minutes in Swift

IosSwiftSetintervalIntervalsRepeat

Ios Problem Overview


How can I run a function every minute? In JavaScript I can do something like setInterval, does something similar exist in Swift?

Wanted output:

Hello World once a minute...

Ios Solutions


Solution 1 - Ios

var helloWorldTimer = NSTimer.scheduledTimerWithTimeInterval(60.0, target: self, selector: Selector("sayHello"), userInfo: nil, repeats: true)

func sayHello() 
{
    NSLog("hello World")
}

Remember to import Foundation.

Swift 4:

 var helloWorldTimer = Timer.scheduledTimer(timeInterval: 60.0, target: self, selector: #selector(ViewController.sayHello), userInfo: nil, repeats: true)
 
 @objc func sayHello() 
 {
     NSLog("hello World")
 }

Solution 2 - Ios

If targeting iOS version 10 and greater, you can use the block-based rendition of Timer, which simplifies the potential strong reference cycles, e.g.:

weak var timer: Timer?

func startTimer() {
    timer?.invalidate()   // just in case you had existing `Timer`, `invalidate` it before we lose our reference to it
    timer = Timer.scheduledTimer(withTimeInterval: 60.0, repeats: true) { [weak self] _ in
        // do something here
    }
}

func stopTimer() {
    timer?.invalidate()
}

// if appropriate, make sure to stop your timer in `deinit`

deinit {
    stopTimer()
}

While Timer is generally best, for the sake of completeness, I should note that you can also use dispatch timer, which is useful for scheduling timers on background threads. With dispatch timers, since they're block-based, it avoids some of the strong reference cycle challenges with the old target/selector pattern of Timer, as long as you use weak references.

So:

var timer: DispatchSourceTimer?

func startTimer() {
    let queue = DispatchQueue(label: "com.domain.app.timer")  // you can also use `DispatchQueue.main`, if you want
    timer = DispatchSource.makeTimerSource(queue: queue)
    timer!.schedule(deadline: .now(), repeating: .seconds(60))
    timer!.setEventHandler { [weak self] in
        // do whatever you want here
    }
    timer!.resume()
}

func stopTimer() {
    timer = nil
}

For more information, see the the Creating a Timer section of Dispatch Source Examples in the Dispatch Sources section of the Concurrency Programming Guide.


For Swift 2, see previous revision of this answer.

Solution 3 - Ios

Here's an update to the NSTimer answer, for Swift 3 (in which NSTimer was renamed to Timer) using a closure rather than a named function:

var timer = Timer.scheduledTimer(withTimeInterval: 60, repeats: true) {
    (_) in
    print("Hello world")
}

Solution 4 - Ios

If you can allow for some time drift here's a simple solution executing some code every minute:

private func executeRepeatedly() {
    // put your code here

    DispatchQueue.main.asyncAfter(deadline: .now() + 60.0) { [weak self] in
        self?.executeRepeatedly()
    }
}

Just run executeRepeatedly() once and it'll be executed every minute. The execution stops when the owning object (self) is released. You also can use a flag to indicate that the execution must stop.

Solution 5 - Ios

You can use Timer (swift 3)

var timer = Timer.scheduledTimerWithTimeInterval(60, target: self, selector: Selector("function"), userInfo: nil, repeats: true)

In selector() you put in your function name

Solution 6 - Ios

In swift 3.0 the GCD got refactored:

let timer : DispatchSourceTimer = DispatchSource.makeTimerSource(flags: [], queue: DispatchQueue.main)

timer.scheduleRepeating(deadline: .now(), interval: .seconds(60))
timer.setEventHandler
{
    NSLog("Hello World")
}
timer.resume()

This is specially useful for when you need to dispatch on a particular Queue. Also, if you're planning on using this for user interface updating, I suggest looking into CADisplayLink as it's synchronized with the GPU refresh rate.

Solution 7 - Ios

Here is another version algrid's answer with an easy way to stop it

@objc func executeRepeatedly() {

    print("--Do something on repeat--")
        
    perform(#selector(executeRepeatedly), with: nil, afterDelay: 60.0)
}

Here's an example of how to start it and stop it:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    executeRepeatedly() // start it
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    NSObject.cancelPreviousPerformRequests(withTarget: self) // stop it
}

Solution 8 - Ios

timer = Timer.scheduledTimer(withTimeInterval: 60, repeats: true, block: myMethod)

func myMethod(_:Timer) {
...
}

or

timer = Timer.scheduledTimer(withTimeInterval: 60, repeats: true) { _ in
...
}

make sure to invalid the timer at some point like your time is no longer visible, or you object is deist

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJOSEFtwView Question on Stackoverflow
Solution 1 - IosUnheiligView Answer on Stackoverflow
Solution 2 - IosRobView Answer on Stackoverflow
Solution 3 - IosJohn TView Answer on Stackoverflow
Solution 4 - IosalgridView Answer on Stackoverflow
Solution 5 - IosBasView Answer on Stackoverflow
Solution 6 - IosCanView Answer on Stackoverflow
Solution 7 - IosLance SamariaView Answer on Stackoverflow
Solution 8 - IosNathan DayView Answer on Stackoverflow