Jak korzystać z Timera (wcześniej NSTimer) w Swift?

257

próbowałem

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

Ale mam błąd mówiąc

'(timeInterval: $T1, target: ViewController, selector: () -> (), userInfo: NilType, repeats: Bool) -> $T6' is not identical to 'NSTimer'
użytkownik3225917
źródło
1
„Jak mogę używać NSTimer w Swift?” - w ten sam sposób, w jaki używasz go w Celu-C. Jego interfejs API nie zmienił się.
Paramagnetyczny rogalik

Odpowiedzi:

534

To zadziała:

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
}

W przypadku Swift 4 metoda, którą chcesz uzyskać, musi być wystawiona na cel C, a zatem @objcatrybut musi zostać dodany do deklaracji metody.

Oscar Swanros
źródło
2
Dodałbym, że klasa z tymi metodami musi być obiektem NSObject, w przeciwnym razie skończy się nierozpoznany błąd selektora
Joshua
27
Od wersji Xcode 6.1 musiałem dodać „@objc” do nagłówka funkcji w następujący sposób: „@objc func update () {”. Bez tego aplikacja ulega awarii przy pierwszym pożarze.
kev
Możesz zadeklarować Var timer: NSTimer! początkowo i używaj go w razie potrzeby!
Nigilan
1
Być może bardziej przydatna wersja składni bloku: let timer = Timer.scheduledTimer (withTimeInterval: timeout, repeats: false) {_ in print („Done.”)}
Teo Sartori
Nie można użyć opcji „let timer = Timer (timeInterval: 0.4, powtórzenia: true) {_ w wersji drukowanej („ Gotowe! ”)}” Nie spowoduje uruchomienia stopera, a następnie nie będzie można go powtórzyć. Musisz użyć Timer.scheduledTimer.
Siamaster
149

Powtarzające się wydarzenie

Możesz użyć timera, aby wykonać akcję wiele razy, jak pokazano w poniższym przykładzie. Timer wywołuje metodę aktualizacji etykiety co pół sekundy.

wprowadź opis zdjęcia tutaj

Oto kod do tego:

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

Opóźnione zdarzenie

Możesz także użyć timera, aby zaplanować jednorazowe wydarzenie na jakiś czas w przyszłości. Główną różnicą w stosunku do powyższego przykładu jest to, że używasz repeats: falsezamiast true.

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

Powyższy przykład wywołuje metodę nazwaną delayedActiondwie sekundy po ustawieniu timera. To się nie powtarza, ale możesz zadzwonić, timer.invalidate()jeśli musisz anulować wydarzenie, zanim ono nastąpi.

Notatki

Związane z

Suragch
źródło
1
@raddevus, dzięki za poinformowanie mnie. Usunąłem stary komentarz do Swift 3.
Suragch,
31

Zaktualizowano do Swift 4, wykorzystując 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
źródło
2
Pokaż działający przykład, co oznaczają słowa „niestandardowe” i „dane”, jeśli funkcja oczekuje NSTimerobiektu
Carlos.V
1
To naprawdę nie ma znaczenia. Możesz zapisać wszystko, czego potrzebujesz, w słowniku userInfo, w tym przypadku jest to dowolna para klucz-wartość.
igraczech
Jest to przydatne, ale zepsuło się w Swift 3, działającym przykładzie: Timer.scheduledTimer (timeInterval: 1.0, target: self, selektor: #selector (event), userInfo: „Info Sent”, powtarza: prawda)
Bobby
28

W systemie iOS 10 dostępna jest również nowa metoda oparta na blokach, która jest bardziej przejrzysta niż użycie selektora:

    _ = Timer.scheduledTimer(withTimeInterval: 5, repeats: false) { timer in
        label.isHidden = true
    }
Josh Homann
źródło
1
Jak to robisz, czy nie lepiej byłoby po prostu usunąć _ = i zacząć od początku Timer?
Honey,
2
Możesz pominąć _ =, jeśli wyciszysz ostrzeżenie o niewykorzystanej wartości lub po prostu nie przejmujesz się ostrzeżeniami. Nie lubię sprawdzać kodu z ostrzeżeniami.
Josh Homann
22

Swift 3, wcześniejszy niż 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)
      }
    }

Notatki

  • Musi znajdować się w głównej kolejce
  • Funkcja oddzwaniania może być publiczna, prywatna, ...
  • Funkcja oddzwaniania musi być @objc
onmyway133
źródło
1
Rozumiem, że tylko oddzwanianie z timerem powinno być w głównej kolejce i że następujące byłyby nieco bardziej wydajne: self.timer = Timer.scheduledTimer (withTimeInterval: 20, powtarza: fałsz) {timer w DispatchQueue.main.async {print (timer)}}
Mathieu Frenette
Mój minutnik nie uruchamiał się z jednego z moich Obiektów i to
Reimond Hill
@ReimondHill Musisz się zmienićtimeInterval
onmyway133
17

Sprawdź z:

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
źródło
2
Próbowałem już, ale napisano: „Nie można znaleźć przeciążenia dla„ init ”, które akceptuje
podane
1
To samo tutaj, otrzymałem błąd „Nie można znaleźć przeciążenia dla„ init ”, który akceptuje dostarczone argumenty”. Czy ta linia naprawdę działa?
Yangshun Tay
Otrzymuję ten sam błąd co @yangshun. Jakim typem obiektu musi selfbyć? UIView jest w porządku?
SimplGy
@SimpleAsCouldBe: tak, to jest w porządku
poseł Midhun,
func kwotaSubmitSuccess () {self.view.hideToastActivity () self.view.makeToast (komunikat: „Kwota pomyślnie zarejestrowana”) var timer = NSTimer.scheduledTimerWithTimeInterval (0,5, cel: self, selektor: „moveToBidderPage”, userInfo: zero, repeats: false)} func moveToBidderPage () {let loginPageView = self.storyboard? .instantiateViewControllerWithIdentifier ("bidderpageID") as! BidderPage self.navigationController? .PushViewController (loginPageView, animowany: true)}
AG
11

W Swift 3 będziesz musiał użyć Timera zamiast NSTimer.

Oto przykład:

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
źródło
11

Szybki 5

Osobiście wolę Timer z zamknięciem blokowym:

    Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { (_) in
       // TODO: - whatever you want
    }
Wissa
źródło
Pamiętaj, że jest to dostępne tylko w systemie macOS 10.12 lub nowszym. Nie jestem pewien co do iOS.
jeff-h
Jest również dostępny w iOS.
Wissa,
7

dla swift 3 i Xcode 8.2 (fajnie mieć bloki, ale jeśli kompilujesz dla iOS9 ORAZ chcesz userInfo):

...

        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
źródło
6

SimpleTimer (Swift 3.1)

Czemu?

Jest to prosta klasa timera w trybie szybkim, która umożliwia:

  • Lokalny licznik czasu
  • Łańcuchowe
  • Jeden wkładki
  • Używaj zwykłych połączeń zwrotnych

Stosowanie:

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

Kod:

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()
    }
}
eonista
źródło
Jak zatrzymać stoper wewnątrz tego bloku na niektórych warunkach?
Mobile Developer iOS Android
Po prostu zapisz referencję do timera w klasie, a następnie po prostu zadzwoń do stop. Kompilator xcode powie ci, czy potrzebuje ucieczki itp.
eonist
3
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(createEnemy), userInfo: nil, repeats: true)

I stwórz zabawę po nazwie createEnemy

fund createEnemy ()
{
do anything ////
}
Khaled Hamdy
źródło
3

Najpierw zadeklaruj swój licznik czasu

var timer: Timer?

Następnie dodaj wiersz w viewDidLoad () lub w dowolnej funkcji, którą chcesz uruchomić stoper

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

Jest to funkcja, którą oddzwonisz, aby zrobić coś, co musi być @objc

@objc func action () {
print("done")
}
geniusz
źródło
2

W Swift 3 coś takiego z @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
źródło
1

Jeśli zainicjujesz metodę timera

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

func update(_ timer : Timer) {

}

następnie dodaj go do pętli, używając metody inny selektor nie będzie wywoływany

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

UWAGA: Jeśli chcesz, aby to powtarzało się, powtórz prawdę i zachowaj odniesienie do timera, w przeciwnym razie metoda aktualizacji nie zostanie wywołana.

Jeśli używasz tej metody.

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

zachowaj odniesienie do późniejszego użycia, jeśli powtórzenia są prawdziwe.

Surjeet Rajput
źródło
0

Próbowałem zrobić w klasie NSObject i to zadziałało dla mnie:

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300)) {  
print("Bang!") }
Álvaro Agüero
źródło
-2

NSTimer został przemianowany na Timer w Swift 4.2. ta składnia będzie działać w wersji 4.2:

let timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(UIMenuController.update), userInfo: nil, repeats: true)
Jamtrax Reunion
źródło
Zmiana nazwy nastąpiła w Swift 3, a inne odpowiedzi już dokonały aktualizacji ...
Eric Aya