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'
user3225917
quelle
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.

Oscar Swanros
quelle
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

Suragch
quelle
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)
    }

}
igraczech
quelle
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
    }
Josh Homann
quelle
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
onmyway133
quelle
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)
Midhun MP
quelle
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
}
Ondrej Kvasnovsky
quelle
11

Swift 5

Ich persönlich bevorzuge den Timer mit dem Blockschluss:

    Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { (_) in
       // TODO: - whatever you want
    }
Wissa
quelle
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)
    }
ingconti
quelle
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()
    }
}
Eonist
quelle
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 ////
}
Khaled Hamdy
quelle
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")
}
Genius
quelle
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()
}
Nik Kov
quelle
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.

Surjeet Rajput
quelle
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!") }
Álvaro Agüero
quelle
-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)
Jamtrax Reunion
quelle
Die Umbenennung erfolgte in Swift 3 und andere Antworten haben das Update bereits durchgeführt ...
Eric Aya