Wie kann ich Timer (früher NSTimer) in Swift verwenden?


257

Ich habe es versucht

var timer = NSTimer()
timer(timeInterval: 0.01, target: self, selector: update, userInfo: nil, repeats: false)

Aber ich habe einen Fehler bekommen

'(timeInterval: $T1, target: ViewController, selector: () -> (), userInfo: NilType, repeats: Bool) -> $T6' is not identical to 'NSTimer'

1
"Wie kann ich NSTimer in Swift verwenden?" - genauso wie Sie es in Objective-C verwenden. Die API hat sich nicht geändert.
Das paramagnetische Croissant

Antworten:


534

Das wird funktionieren:

override func viewDidLoad() {
    super.viewDidLoad()
    // Swift block syntax (iOS 10+)
    let timer = Timer(timeInterval: 0.4, repeats: true) { _ in print("Done!") }
    // Swift >=3 selector syntax
    let timer = Timer.scheduledTimer(timeInterval: 0.4, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)
    // Swift 2.2 selector syntax
    let timer = NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: #selector(MyClass.update), userInfo: nil, repeats: true)
    // Swift <2.2 selector syntax
    let timer = NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: "update", userInfo: nil, repeats: true)
}

// must be internal or public. 
@objc func update() {
    // Something cool
}

Für Swift 4 muss die Methode, für die Sie den Selektor erhalten möchten, Objective-C verfügbar gemacht werden. Daher @objcmuss der Methodendeklaration ein Attribut hinzugefügt werden.


2
Ich würde hinzufügen, dass die Klasse mit diesen Methoden ein NSObject sein muss, sonst erhalten Sie einen nicht erkannten Selektorfehler
Joshua

27
Ab Xcode 6.1 musste ich dem Funktionsheader "@objc" wie folgt hinzufügen: "@objc func update () {". Ohne sie stürzt die App beim ersten Brand ab.
Kev

Sie können Var timer deklarieren: NSTimer! zunächst und bei Bedarf verwenden!
Nigilan

1
Eine vielleicht nützlichere Version der Blocksyntax: let timer = Timer.scheduledTimer (withTimeInterval: timeout, repeats: false) {_ in print ("Done.")}
Teo Sartori

Sie können 'let timer = Timer (timeInterval: 0.4, repeats: true) {_ in print ("Done!")}' Nicht verwenden. Dadurch wird der Timer nicht gestartet und Sie können ihn nicht wiederholen. Sie müssen Timer.scheduledTimer verwenden.
Siamaster

149

Wiederholtes Ereignis

Sie können einen Timer verwenden, um eine Aktion mehrmals auszuführen, wie im folgenden Beispiel gezeigt. Der Timer ruft eine Methode auf, um eine Beschriftung jede halbe Sekunde zu aktualisieren.

Geben Sie hier die Bildbeschreibung ein

Hier ist der Code dafür:

import UIKit

class ViewController: UIViewController {

    var counter = 0
    var timer = Timer()

    @IBOutlet weak var label: UILabel!

    // start timer
    @IBAction func startTimerButtonTapped(sender: UIButton) {
        timer.invalidate() // just in case this button is tapped multiple times

        // start the timer
        timer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
    }

    // stop timer
    @IBAction func cancelTimerButtonTapped(sender: UIButton) {
        timer.invalidate()
    }

    // called every time interval from the timer
    func timerAction() {
        counter += 1
        label.text = "\(counter)"
    }
}

Verspätetes Ereignis

Sie können auch einen Timer verwenden, um ein einmaliges Ereignis für einige Zeit in der Zukunft zu planen. Der Hauptunterschied zum obigen Beispiel besteht darin, dass Sie repeats: falseanstelle von verwenden true.

timer = Timer.scheduledTimer(timeInterval: 2.0, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false)

Im obigen Beispiel wird eine Methode mit dem Namen delayedActionzwei Sekunden nach dem Einstellen des Timers aufgerufen. Es wird nicht wiederholt, aber Sie können trotzdem anrufentimer.invalidate() wenn Sie das Ereignis abbrechen müssen, bevor es jemals auftritt.

Anmerkungen

  • Wenn die Möglichkeit besteht, Ihre Timer-Instanz mehrmals zu starten, stellen Sie sicher, dass Sie zuerst die alte Timer-Instanz ungültig machen. Andernfalls verlieren Sie den Verweis auf den Timer und können ihn nicht mehr stoppen. (siehe diese Fragen und Antworten )
  • Verwenden Sie keine Timer, wenn sie nicht benötigt werden. Weitere Informationen finden Sie im Abschnitt Timer des Energieeffizienzhandbuchs für iOS-Apps .

verbunden


1
@raddevus, danke, dass du mich informiert hast. Ich habe den alten Swift 3-Kommentar entfernt.
Suragch

31

Aktualisiert auf Swift 4 unter Nutzung von userInfo:

class TimerSample {

    var timer: Timer?

    func startTimer() {
        timer = Timer.scheduledTimer(timeInterval: 5.0,
                                     target: self,
                                     selector: #selector(eventWith(timer:)),
                                     userInfo: [ "foo" : "bar" ],
                                     repeats: true)
    }

    // Timer expects @objc selector
    @objc func eventWith(timer: Timer!) {
        let info = timer.userInfo as Any
        print(info)
    }

}

2
Zeigen Sie ein funktionierendes Beispiel, was "benutzerdefiniert" und "Daten" bedeuten, wenn die Funktion ein NSTimerObjekt erwartet
Carlos.V

1
Es ist wirklich egal. Sie können alles, was Sie benötigen, im userInfo-Wörterbuch speichern. In diesem Fall handelt es sich um ein beliebiges Schlüssel-Wert-Paar.
igraczech

Dies ist nützlich, brach jedoch in Swift 3 ein, Arbeitsbeispiel: Timer.scheduledTimer (timeInterval: 1.0, Ziel: self, Selektor: #selector (Ereignis), userInfo: "Info Sent", Wiederholungen: true)
Bobby

28

Ab iOS 10 gibt es auch eine neue blockbasierte Timer-Factory-Methode, die sauberer ist als die Verwendung des Selektors:

    _ = Timer.scheduledTimer(withTimeInterval: 5, repeats: false) { timer in
        label.isHidden = true
    }

1
Wäre es nicht besser, das zu entfernen _ = und einfach damit zu beginnen Timer?
Honey

2
Sie können das _ = weglassen, wenn Sie die Warnung über den nicht verwendeten Wert stummschalten oder wenn Sie sich nur nicht um Warnungen kümmern. Ich mag es nicht, Code mit Warnungen einzuchecken.
Josh Homann

22

Swift 3, vor iOS 10

func schedule() {
    DispatchQueue.main.async {
      self.timer = Timer.scheduledTimer(timeInterval: 20, target: self,
                                   selector: #selector(self.timerDidFire(timer:)), userInfo: nil, repeats: false)
    }
  }

  @objc private func timerDidFire(timer: Timer) {
    print(timer)
  }

Swift 3, iOS 10+

DispatchQueue.main.async {
      self.timer = Timer.scheduledTimer(withTimeInterval: 20, repeats: false) { timer in
        print(timer)
      }
    }

Anmerkungen

  • Es muss sich in der Hauptwarteschlange befinden
  • Die Rückruffunktion kann öffentlich, privat, ...
  • Rückruffunktion muss sein @objc

1
Nach meinem Verständnis sollte sich nur der Timer-Rückruf in der Hauptwarteschlange befinden und Folgendes wäre etwas effizienter: self.timer = Timer.scheduledTimer (withTimeInterval: 20, repeats: false) {timer in DispatchQueue.main.async {print (Timer)}}
Mathieu Frenette

Mein Timer wurde nicht von einem meiner Objekte ausgelöst und das machte den Trick :)
Reimond Hill

@ReimondHill Sie müssen änderntimeInterval
onmyway133

17

Überprüfen Sie mit:

Swift 2

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

Swift 3, 4, 5

var timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)

2
Ich habe es bereits versucht, aber es heißt 'Es konnte keine Überladung für' init 'gefunden werden, die die angegebenen Argumente akzeptiert'
user3225917

1
Gleich hier habe ich den Fehler 'Es konnte keine Überladung für' init 'gefunden werden, die die angegebenen Argumente akzeptiert' erhalten. Funktioniert diese Linie wirklich?
Yangshun Tay

Ich erhalte den gleichen Fehler wie @yangshun. Welche Art von Objekt muss selfsein? UIView ist in Ordnung?
SimplGy

@SimpleAsCouldBe: Ja, das ist in
Ordnung

func amountSubmitSuccess () {self.view.hideToastActivity () self.view.makeToast (Nachricht: "Der erfolgreich registrierte Betrag") var timer = NSTimer.scheduledTimerWithTimeInterval (0.5, target: self, selector: "moveToBidderPage", userInfo: nil, Wiederholungen: false)} func moveToBidderPage () {let loginPageView = self.storyboard? .instantiateViewControllerWithIdentifier ("bidderpageID") as! BidderPage self.navigationController? .PushViewController (loginPageView, animiert: true)}
AG

11

In Swift 3 müssen Sie Timer anstelle von NSTimer verwenden.

Hier ist ein Beispiel:

Timer.scheduledTimer(timeInterval: 1, 
    target: self, 
    selector: #selector(YourController.update), 
    userInfo: nil, 
    repeats: true)

// @objc selector expected for Timer
@objc func update() {
    // do what should happen when timer triggers an event
}

11

Swift 5

Ich persönlich bevorzuge den Timer mit dem Blockschluss:

    Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { (_) in
       // TODO: - whatever you want
    }

Beachten Sie, dass dies nur in macOS 10.12 oder neuer verfügbar ist. Ich bin mir nicht sicher über ios.
Jeff-h

Es ist auch in iOS verfügbar.
Wissa

7

für Swift 3 und Xcode 8.2 (schön, Blöcke zu haben, aber wenn Sie für iOS9 kompilieren UND userInfo wollen):

...

        self.timer = Timer(fireAt: fire,
                           interval: deltaT,
                           target: self,
                           selector: #selector(timerCallBack(timer:)),
                           userInfo: ["custom":"data"],
                           repeats: true)

        RunLoop.main.add(self.timer!, forMode: RunLoopMode.commonModes)
        self.timer!.fire()
}

func timerCallBack(timer: Timer!){
        let info = timer.userInfo
        print(info)
    }

6

SimpleTimer (Swift 3.1)

Warum?

Dies ist eine einfache Timer-Klasse in Swift, mit der Sie:

  • Timer mit lokalem Gültigkeitsbereich
  • Verkettbar
  • Ein Liner
  • Verwenden Sie regelmäßige Rückrufe

Verwendung:

SimpleTimer(interval: 3,repeats: true){print("tick")}.start()//Ticks every 3 secs

Code:

class SimpleTimer {/*<--was named Timer, but since swift 3, NSTimer is now Timer*/
    typealias Tick = ()->Void
    var timer:Timer?
    var interval:TimeInterval /*in seconds*/
    var repeats:Bool
    var tick:Tick

    init( interval:TimeInterval, repeats:Bool = false, onTick:@escaping Tick){
        self.interval = interval
        self.repeats = repeats
        self.tick = onTick
    }
    func start(){
        timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(update), userInfo: nil, repeats: true)//swift 3 upgrade
    }
    func stop(){
        if(timer != nil){timer!.invalidate()}
    }
    /**
     * This method must be in the public or scope
     */
    @objc func update() {
        tick()
    }
}

Wie kann man dann den Timer in diesem Block unter bestimmten Bedingungen stoppen?
Mobile Entwickler iOS Android

Speichern Sie den Ref einfach im Timer in einer Klasse und rufen Sie einfach stop an. Der Xcode-Compiler wird Ihnen sagen, ob es Flucht usw. braucht
Eonist

3
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(createEnemy), userInfo: nil, repeats: true)

Und Spaß mit dem Namen createEnemy schaffen

fund createEnemy ()
{
do anything ////
}

3

Deklarieren Sie zuerst Ihren Timer

var timer: Timer?

Fügen Sie dann eine Zeile in viewDidLoad () oder in einer beliebigen Funktion hinzu, mit der Sie den Timer starten möchten

timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(action), userInfo: nil, repeats: false)

Dies ist die Funktion, die Sie zurückrufen werden, um etwas zu tun, das @objc sein muss

@objc func action () {
print("done")
}

2

In Swift 3 so etwas mit @objc:

func startTimerForResendingCode() {
    let timerIntervalForResendingCode = TimeInterval(60)
    Timer.scheduledTimer(timeInterval: timerIntervalForResendingCode,
                         target: self,
                         selector: #selector(timerEndedUp),
                         userInfo: nil,
                         repeats: false)
}




@objc func timerEndedUp() {
    output?.timerHasFinishedAndCodeMayBeResended()
}

1

Wenn Sie die Methode des Timers einleiten

let timer = Timer(timeInterval: 3, target: self, selector: #selector(update(_:)), userInfo: [key : value], repeats: false)

func update(_ timer : Timer) {

}

Fügen Sie es dann mit der Methode zur Schleife hinzu. Ein anderer Selektor wird nicht aufgerufen

RunLoop.main.add(timer!, forMode: .defaultRunLoopMode)

HINWEIS: Wenn Sie möchten, dass sich dies wiederholt, machen Sie Wiederholungen wahr und behalten Sie die Referenz des Timers bei, da sonst die Aktualisierungsmethode nicht aufgerufen wird.

Wenn Sie diese Methode verwenden.

Timer.scheduledTimer(timeInterval: seconds, target: self, selector: #selector(update(_:)), userInfo: nil, repeats: true)

Bewahren Sie eine Referenz für die spätere Verwendung auf, wenn Wiederholungen zutreffen.


0

Ich habe versucht, in einer NSObject-Klasse zu arbeiten, und das hat bei mir funktioniert:

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300)) {  
print("Bang!") }

-2

NSTimer wurde in Swift 4.2 in Timer umbenannt. Diese Syntax funktioniert in 4.2:

let timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(UIMenuController.update), userInfo: nil, repeats: true)

Die Umbenennung erfolgte in Swift 3 und andere Antworten haben das Update bereits durchgeführt ...
Eric Aya
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.