web-dev-qa-db-fra.com

Faites quelque chose toutes les x minutes dans Swift

Comment puis-je exécuter une fonction toutes les minutes? En JavaScript, je peux faire quelque chose comme setInterval, existe-t-il quelque chose de similaire dans Swift?

Sortie recherchée:

Bonjour le monde une fois par minute ...

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

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

N'oubliez pas d'importer 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")
 }
157
Unheilig

Dans Swift 3, vous pouvez créer un Timer. Et si vous ciblez iOS version 10 ou supérieure, vous pouvez utiliser le rendu par blocs, ce qui simplifie les cycles de référence forts potentiels, par exemple:

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()
}

Dans Swift 2, vous créez une NSTimer. Et si vous utilisez Swift 2, vous utiliserez peut-être une version iOS antérieure à la version 10.0, auquel cas vous devrez utiliser l'ancien modèle target/selector:

weak var timer: NSTimer?

func startTimer() {
    timer?.invalidate()   // just in case you had existing `NSTimer`, `invalidate` it before we lose our reference to it
    timer = NSTimer.scheduledTimerWithTimeInterval(60.0, target: self, selector: #selector(handleTimer(_:)), userInfo: nil, repeats: true)
}

func handleTimer(timer: NSTimer) {
    // do something here
}

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

// because this old target/selector approach will keep a strong reference
// to the `target`, if you want the timer to stop when the view controller
// is dismissed, you can't stop the timer in `deinit`, but rather have to 
// detect the dismissing of the view controller using other mechanisms. Commonly,
// we used to detect the view disappearing, like below:

override func viewDidDisappear(animated: Bool) {
    super.viewDidDisappear(animated)
    stopTimer()
}

Bien que NSTimer soit généralement préférable, pour des raisons d'exhaustivité, il convient de noter que vous pouvez également utiliser le temporisateur de répartition, ce qui est utile pour planifier des temporisateurs sur des threads d'arrière-plan. Avec les temporisateurs de dispatch, étant donné qu'ils sont basés sur des blocs, cela évite certains des défis de cycle de référence importants avec l'ancien modèle target/selector de NSTimer, tant que vous utilisez weak références.

Donc, dans Swift 3:

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!.scheduleRepeating(deadline: .now(), interval: .seconds(60))
    timer!.setEventHandler { [weak self] in
        // do whatever you want here
    }
    timer!.resume()
}

func stopTimer() {
    timer?.cancel()
    timer = nil
}

deinit {
    self.stopTimer()
}

Dans Swift 2:

var timer: dispatch_source_t?

func startTimer() {
    let queue = dispatch_queue_create("com.domain.app.timer", nil) // again, you can use `dispatch_get_main_queue()` if you want to use the main queue
    timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue)
    dispatch_source_set_timer(timer!, DISPATCH_TIME_NOW, 60 * NSEC_PER_SEC, 1 * NSEC_PER_SEC) // every 60 seconds, with leeway of 1 second
    dispatch_source_set_event_handler(timer!) { [weak self] in
        // do whatever you want here
    }
    dispatch_resume(timer!)
}

func stopTimer() {
    if let timer = timer {
        dispatch_source_cancel(timer)
        self.timer = nil
    }
}

deinit {
    self.stopTimer()
}

Pour plus d'informations, voir la section Création d'un temporisateur dans Exemples de source d'affectation dans la section Dispatch Sources du Guide de programmation en simultanéité .

126
Rob

Voici une mise à jour de la réponse NSTimer, pour Swift 3 (dans lequel NSTimer a été renommé en Timer) à l'aide d'une fermeture plutôt que d'une fonction nommée:

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

Vous pouvez utiliser NSTimer

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

Dans selector () vous mettez dans le nom de votre fonction

11
Bas

Si vous pouvez autorisez une certaine dérive temporelle, voici une solution simple qui exécute du code toutes les minutes:

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

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

Il suffit de lancer executeRepeatedly() une fois et il sera exécuté toutes les minutes. L'exécution s'arrête lorsque l'objet propriétaire (self) est libéré. Vous pouvez également utiliser un indicateur pour indiquer que l'exécution doit être interrompue.

9
algrid

Dans Swift 3.0, le GCD a été refactoré:

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

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

Ceci est particulièrement utile lorsque vous avez besoin d'envoyer sur une file d'attente particulière. De plus, si vous prévoyez d’utiliser cette fonctionnalité pour la mise à jour de l’interface utilisateur, je vous suggère d’examiner la méthode CADisplayLink car elle est synchronisée avec le taux de rafraîchissement du processeur graphique.

7
Can