Como posso usar o Timer (anteriormente NSTimer) no Swift?

257

eu tentei

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

Mas, recebi um erro dizendo

'(timeInterval: $T1, target: ViewController, selector: () -> (), userInfo: NilType, repeats: Bool) -> $T6' is not identical to 'NSTimer'
user3225917
fonte
1
"Como posso usar o NSTimer no Swift?" - da mesma maneira que você o usa no Objective-C. Sua API não mudou.
O Croissant Paramagnético

Respostas:

535

Isso funcionará:

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
}

Para o Swift 4, o método do qual você deseja obter o seletor deve ser exposto ao Objective-C, portanto, o @objcatributo deve ser adicionado à declaração do método.

Oscar Swanros
fonte
2
Eu acrescentaria que a classe com estes métodos precisa ser um NSObject, senão você acaba com um erro selector não reconhecido
Joshua
27
No Xcode 6.1, eu tive que adicionar "@objc" ao cabeçalho da função assim: "@objc func update () {". Sem ele, o aplicativo trava após o primeiro disparo.
Kev
Você pode declarar Var timer: NSTimer! inicialmente e use-o sempre que necessário!
Nigilan 01/09/2015
1
Uma versão talvez mais útil da sintaxe do bloco: vamos timer = Timer.scheduledTimer (withTimeInterval: timeout, repete: false) {_ na imprensa ( "Feito")}
Teo Sartori
Você não pode usar 'let timer = Timer (timeInterval: 0.4, repete: true) {_ na impressão ("Concluído!")}' 'Isso não iniciará o timer e você não poderá repeti-lo. Você deve usar Timer.scheduledTimer.
Siamaster 29/03/19
149

Evento repetido

Você pode usar um cronômetro para executar uma ação várias vezes, como visto no exemplo a seguir. O timer chama um método para atualizar um rótulo a cada meio segundo.

insira a descrição da imagem aqui

Aqui está o código para isso:

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

Evento atrasado

Você também pode usar um cronômetro para agendar um evento único por algum tempo no futuro. A principal diferença do exemplo acima é que você usa em repeats: falsevez de true.

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

O exemplo acima chama um método chamado delayedActiondois segundos após o timer ser definido. Não é repetido, mas você ainda pode ligar timer.invalidate()se precisar cancelar o evento antes que ele aconteça.

Notas

  • Se houver alguma chance de iniciar sua instância de timer várias vezes, certifique-se de invalidar a instância de timer antiga primeiro. Caso contrário, você perde a referência ao temporizador e não pode mais pará-lo. (veja estas perguntas e respostas )
  • Não use temporizadores quando não forem necessários. Consulte a seção temporizadores do Guia de eficiência energética para aplicativos iOS .

Relacionado

Suragch
fonte
1
@raddevus, obrigado por me informar. Eu removi o antigo comentário do Swift 3.
Suragch
31

Atualizado para o Swift 4, aproveitando as informações do usuário:

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
fonte
2
Mostrar um exemplo de trabalho, o que significa "costume" e "dados" significa se a função está esperando um NSTimerobjeto
Carlos.V
1
Isso realmente não importa. Você pode armazenar tudo o que precisar no dicionário userInfo; nesse caso, é um par arbitrário de valor-chave.
precisa saber é o seguinte
Isso é útil, mas foi interrompido no Swift 3, exemplo de trabalho: Timer.scheduledTimer (timeInterval: 1.0, target: self, seletor: #selector (evento), userInfo: "Informações enviadas", repete: true)
Bobby
28

No iOS 10, também existe um novo método de fábrica do Timer baseado em blocos, mais limpo que o seletor:

    _ = Timer.scheduledTimer(withTimeInterval: 5, repeats: false) { timer in
        label.isHidden = true
    }
Josh Homann
fonte
1
Do jeito que você está fazendo isso, não seria melhor apenas remover o _ = e começar Timer?
Mel
2
Você pode omitir _ = se silenciar o aviso sobre o valor não utilizado ou se simplesmente não se importar com avisos. Não gosto de verificar o código com avisos.
Josh Homann
22

Swift 3, pré 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 ou superior

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

Notas

  • Ele precisa estar na fila principal
  • A função de retorno de chamada pode ser pública, privada, ...
  • A função de retorno de chamada precisa ser @objc
onmyway133
fonte
1
Meu entendimento é que apenas o retorno de chamada do timer deve estar na fila principal e que o seguinte seria um pouco mais eficiente: self.timer = Timer.scheduledTimer (withTimeInterval: 20, repetições: false) {timer em DispatchQueue.main.async {print (timer)}}
Mathieu Frenette
Meu timer não foi desencadeante de um dos meus objetos e que fez o truque :)
Reimond Colina
@ReimondHill Você precisa mudartimeInterval
onmyway133
17

Verificar com:

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
fonte
2
Eu já tentei, mas ele diz 'Não foi possível encontrar uma sobrecarga para' init 'que aceita os argumentos fornecidos' '
user3225917
1
Mesmo aqui, recebi o erro 'Não foi possível encontrar uma sobrecarga para' init 'que aceita os argumentos fornecidos'. Essa linha realmente funciona?
Yangshun Tay
Eu recebo o mesmo erro que @yangshun. Que tipo de objeto deve selfser? UIView está ok?
SimplGy
@SimpleAsCouldBe: sim, está tudo bem #
Midhun MP 10/06
func amountSubmitSuccess () {self.view.hideToastActivity () self.view.makeToast (mensagem: "A quantidade registrada com sucesso") var timer = NSTimer.scheduledTimerWithTimeInterval (0.5, destino: self, seletor: "moveToBidderPage", userInfo: nil, repete: false)} func moveToBidderPage () {deixe loginPageView = self.storyboard? .instantiateViewControllerWithIdentifier ("bidderpageID") as! BidderPage self.navigationController? .PushViewController (loginPageView, animated: true)}
AG
11

Você precisará usar o Timer em vez do NSTimer no Swift 3.

Aqui está um exemplo:

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
fonte
11

Swift 5

Pessoalmente, prefiro o Timer com o fechamento do bloco:

    Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { (_) in
       // TODO: - whatever you want
    }
Wissa
fonte
Esteja ciente de que isso só está disponível no macOS 10.12 ou mais recente. Não tenho certeza sobre o ios.
Jeff-h
Também está disponível no iOS.
Wissa
7

para swift 3 e Xcode 8.2 (é bom ter blocos, mas se você compilar para iOS9 E desejar informações do usuário):

...

        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
fonte
6

SimpleTimer (Swift 3.1)

Por quê?

Esta é uma classe simples de timer no swift que permite:

  • Temporizador com escopo local
  • Chainable
  • Um forros
  • Use retornos de chamada regulares

Uso:

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

Código:

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
fonte
Como parar o cronômetro dentro desse bloco em algumas condições?
Desenvolvedor Mobile iOS Android
Apenas armazene o árbitro no cronômetro em uma classe e depois chame stop. O compilador xcode lhe dirá se precisa escapar etc.
eonist
3
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(createEnemy), userInfo: nil, repeats: true)

E criar diversão com o nome createEnemy

fund createEnemy ()
{
do anything ////
}
Khaled Hamdy
fonte
3

Primeiro declare seu cronômetro

var timer: Timer?

Em seguida, adicione linha em viewDidLoad () ou em qualquer função que você deseja iniciar o timer

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

Esta é a função que você retornará para fazer algo que deve ser @objc

@objc func action () {
print("done")
}
gênio
fonte
2

No Swift 3, algo assim com @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
fonte
1

Se você iniciar o método do temporizador

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

func update(_ timer : Timer) {

}

adicione-o ao loop usando o método outro seletor não será chamado

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

NOTA: Se você deseja que isso repita, faça repetições verdadeiras e mantenha a referência do temporizador, caso contrário, o método de atualização não será chamado.

Se você estiver usando este método.

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

mantenha uma referência para uso posterior se a repetição for verdadeira.

Surjeet Rajput
fonte
0

Eu tentei fazer em uma classe NSObject e isso funcionou para mim:

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300)) {  
print("Bang!") }
Álvaro Agüero
fonte
-2

O NSTimer foi renomeado para Timer no Swift 4.2. esta sintaxe funcionará no 4.2:

let timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(UIMenuController.update), userInfo: nil, repeats: true)
Jamtrax Reunion
fonte
A renomeação aconteceu no Swift 3 e outras respostas já fizeram a atualização ...
Eric Aya