Mach alle x Minuten etwas in Swift

112

Wie kann ich jede Minute eine Funktion ausführen? In JavaScript kann ich so etwas machensetInterval , gibt es in Swift etwas Ähnliches?

Gewünschte Ausgabe:

Hallo Welt einmal in der Minute ...

JOSEFtw
quelle
Aktualisiert für Swift 2: Swift Timer
JamesG
Wie kann ich das in Ziel C machen?
Radames E. Hernandez

Antworten:

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

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

Denken Sie daran, Foundation zu importieren.

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")
 }
Unheilig
quelle
1
aber was ist, wenn Sie zwischen den Ansichten wechseln möchten? Der Code wird richtig aufhören?
Cing
5
@Cing hängt davon ab, worauf sich selbst bezieht.
Antzi
1
Vergessen Sie nicht , dass NSTimeres das Ziel, so, mit dieser Einstellung behält, wenn helloWorldTimereine Eigenschaft auf selfSie sich ein Zyklus behalten haben, wo selfbehält helloWorldTimerund helloWorldTimerbehält self.
MANIAK_dobrii
@MANIAK_dobrii Können Sie auch kommentieren, wie der Aufbewahrungszyklus unterbrochen werden kann? Wenn der VC entlassen wird, der Timer jedoch nicht abgebrochen wird, ist der Zyklus noch in Takt? Sie müssen also beide den Timer abbrechen und dann die Ansicht schließen, um den Zyklus zu unterbrechen?
Dave G
1
Für Swift 4 muss die Methode, für die Sie den Selektor erhalten möchten, für Objective-C verfügbar gemacht werden. Daher muss das Attribut @objc zur Methodendeklaration hinzugefügt werden. zB `` `@objc func sayHello () {}` ``
Shamim Hossain
136

Wenn Sie auf iOS Version 10 und höher abzielen, können Sie die blockbasierte Wiedergabe von verwenden Timer, die die potenziell starken Referenzzyklen vereinfacht, z.

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

Obwohl dies Timerder Vollständigkeit halber im Allgemeinen am besten ist, sollte ich beachten, dass Sie auch den Versand-Timer verwenden können, der zum Planen von Timern für Hintergrund-Threads nützlich ist. Da Dispatch-Timer blockbasiert sind, werden einige der starken Herausforderungen des Referenzzyklus mit dem alten target/ selectorMuster von vermieden Timer, solange Sie weakReferenzen verwenden.

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?.cancel()
    timer = nil
}

deinit {
    self.stopTimer()
}

Weitere Informationen finden Sie in der das Erstellen eines Timer Abschnitt Versand Quelle Beispiele in der Dispatch - Quellen Abschnitt des Concurrency Programming Guide.


Für Swift 2 siehe vorherige Überarbeitung dieser Antwort .

rauben
quelle
Wie würden Sie bei diesem Ansatz einen Timer wählen, der nur einmal ausgeführt wird?
Juan Boero
@JuanPabloBoero - Ich würde diesen Ansatz nicht für eine einmalige Feuersituation verwenden. Du würdest benutzen dispatch_after. Oder eine sich nicht wiederholende NSTimer.
Rob
@Rob Ich habe eine Zählerbeschriftung auf dem Bildschirm, die jede Sekunde von einer Funktion aktualisiert wird, und ich verwende den obigen Code, um meinen Zähler zu erhöhen und den Beschriftungstext zu aktualisieren. Das Problem ist jedoch, dass meine Zählervariable jede Sekunde aktualisiert wird, der Bildschirm jedoch nicht den neuesten Zählerwert in meinem UILabel anzeigt.
Nagendra Rao
Rao, das Obige ist nützlich, um eine Aktion für einen Hintergrund-Thread auszuführen. Ihre UI-Updates müssen jedoch in der Hauptwarteschlange erfolgen. Planen Sie dies entweder im Hauptthread oder senden Sie die UI-Updates zumindest zurück an den Hauptthread.
Rob
1
Diese Frage gehört hier nicht in die Kommentare zu dieser Antwort. Löschen Sie Ihre Kommentare oben und stellen Sie Ihre eigene Frage. Kurz gesagt, Sie lassen die App im Allgemeinen nicht im Hintergrund laufen, sondern lassen sie nur so aussehen, wie sie war. Siehe stackoverflow.com/a/31642036/1271826 .
Rob
17

Hier ist ein Update der NSTimerAntwort für Swift 3 (in das NSTimerumbenannt wurde Timer), bei dem ein Abschluss anstelle einer benannten Funktion verwendet wird:

var timer = Timer.scheduledTimer(withTimeInterval: 60, repeats: true) {
    (_) in
    print("Hello world")
}
John T.
quelle
6
Das ist nur für iOS 10.
Glenn
Bitte nicht ios 10+ Lösungen posten
Numan Karaaslan
13

Wenn Sie eine gewisse Zeitverschiebung zulassen können , finden Sie hier eine einfache Lösung, mit der jede Minute Code ausgeführt wird:

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

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

Nur executeRepeatedly()einmal ausführen und es wird jede Minute ausgeführt. Die Ausführung wird beendet, wenn das besitzende Objekt ( self) freigegeben wird. Sie können auch ein Flag verwenden, um anzuzeigen, dass die Ausführung gestoppt werden muss.

Algrid
quelle
Diese Entscheidung ist viel bequemer, als all diese Timer zu haben, sie Runloops hinzuzufügen, sie ungültig zu machen ... Cool!
julia_v
Dies scheint eine gültige Lösung zu sein, aber es wird ein
Aufbewahrungszyklus erstellt,
11

Sie können verwenden Timer(schnell 3)

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

In selector () geben Sie Ihren Funktionsnamen ein

Bas
quelle
Wie kannst du es in Swift 3 machen?
bibscy
1
use Timer... NSTimerwurde umbenannt
Joseph
7

In Swift 3.0 wurde die GCD überarbeitet:

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

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

Dies ist besonders nützlich, wenn Sie in einer bestimmten Warteschlange versenden müssen. Wenn Sie dies für die Aktualisierung der Benutzeroberfläche verwenden möchten, sollten Sie prüfen, ob CADisplayLinkes mit der GPU-Aktualisierungsrate synchronisiert ist.

Können
quelle