Как я могу использовать NSTimer в Swift?

231

Я пробовал

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

Но я получил сообщение об ошибке

'(timeInterval: $T1, target: ViewController, selector: () -> (), userInfo: NilType, repeats: Bool) -> $T6' is not identical to 'NSTimer'
  • 1
    "Как я могу использовать NSTimer в Swift?" - так же, как вы используете его в Objective-C. Его API не изменился.
Теги:
nstimer
nstimeinterval

13 ответов

475
Лучший ответ

Это будет работать:

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
}

Для Swift 4, метод, для которого вы хотите получить селектор, должен быть открыт для Objective-C, поэтому атрибут @objc должен быть добавлен в объявление метода.

  • 2
    Я бы добавил, что класс с этими методами должен быть NSObject, в противном случае вы получите нераспознанную ошибку селектора
  • 27
    Начиная с Xcode 6.1, мне приходилось добавлять «@objc» в заголовок функции следующим образом: «@objc func update () {». Без этого приложение вылетает при первом пожаре.
Показать ещё 4 комментария
136

Повторное событие

Вы можете использовать таймер для выполнения действия несколько раз, как показано в следующем примере. Таймер вызывает метод обновления метки каждые полсекунды.

Изображение 1747

Вот код для этого:

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

Отложенное событие

Вы также можете использовать таймер для планирования одноразового события в течение некоторого времени в будущем. Основное отличие от вышеприведенного примера заключается в том, что вы используете repeats: false вместо true.

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

В приведенном выше примере вызывается метод с именем delayedAction две секунды после установки таймера. Он не повторяется, но вы все равно можете вызвать timer.invalidate() если вам нужно отменить событие до его появления.

Заметки

связанные с

  • 0
    Отличный ответ, все еще работает в Swift 4.2 Xcode 10.1.
  • 1
    @raddevus, спасибо, что сообщили мне об этом. Я удалил старый комментарий Swift 3.
26

Обновлено до Swift 4, используя 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
    Покажите рабочий пример, что означают «custom» и «data», если функция ожидает объект NSTimer
  • 1
    Это действительно не имеет значения. Вы можете хранить все, что вам нужно, в словаре userInfo, в данном случае это произвольная пара ключ-значение.
Показать ещё 1 комментарий
22

Как и в iOS 10, также существует новый метод Timer factory на основе блоков, который более чист, чем при использовании селектора:

    _ = Timer.scheduledTimer(withTimeInterval: 5, repeats: false) { timer in
        label.isHidden = true
    }
  • 0
    То, как вы это делаете, не лучше ли просто удалить _ = и начать с Timer ?
  • 1
    Вы можете опустить _ =, если вы отключите предупреждение о неиспользованном значении или если вам просто наплевать на предупреждения. Я не люблю проверять код с предупреждениями.
16

Swift 3, pre 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)
      }
    }

Примечания

  • Он должен находиться в главной очереди
  • Функция обратного вызова может быть общедоступной, частной,...
  • Функция обратного вызова должна быть @objc
  • 1
    Насколько я понимаю, только обратный вызов таймера должен быть в главной очереди, и что следующее будет несколько более эффективным: self.timer = Timer.scheduledTimer (withTimeInterval: 20, repeat: false) {timer in DispatchQueue.main.async {print (таймер)}}
  • 0
    Мой таймер не срабатывал от одного из моих объектов, и это сделало трюк :)
Показать ещё 2 комментария
14

Обратите внимание:

var timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: Selector("update"), userInfo: nil, repeats: true);
  • 2
    Я уже пробовал это, но он говорит: «Не удалось найти перегрузку для« init », который принимает предоставленные аргументы»
  • 0
    @midhun в быстром не имеет ; нет, это правильно или нет
Показать ещё 7 комментариев
10

Вам нужно будет использовать таймер вместо NSTimer в Swift 3.

Вот пример:

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

для быстрых 3 и Xcode 8.2 (приятно иметь блоки, но если вы компилируете для iOS9 И хотите 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)
    }
5

SimpleTimer (Swift 3.1)

Почему?

Это простой класс таймера в swift, который позволяет вам:

  • Локальный таймер
  • змеевидных
  • Один вкладыш
  • Использовать регулярные обратные вызовы

Использование:

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

Код:

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()
    }
}
  • 0
    Как тогда остановить таймер внутри этого блока при некоторых условиях?
  • 0
    Просто сохраните ссылку в таймере в классе, затем просто вызовите стоп. Компилятор xcode сообщит вам, нужно ли ему бежать и т. Д.
2
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(createEnemy), userInfo: nil, repeats: true)

И создать Fun по имени createEnemy

fund createEnemy ()
{
do anything ////
}
  • 0
    Вы должны отформатировать код как код для удобства чтения
2

В Swift 3 что-то вроде этого с @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

Если вы запускаете метод таймера

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

func update(_ timer : Timer) {

}

затем добавьте его в цикл, используя метод другого селектора, который не будет называться

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

ПРИМЕЧАНИЕ. Если вы хотите, чтобы это повторялось, повторите повторение и сохраните ссылку на таймер, иначе метод обновления не будет вызываться.

Если вы используете этот метод.

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

сохраните ссылку для последующего использования, если повторы верны.

0

NSTimer был переименован в Timer в Swift 4.2. этот синтаксис будет работать в 4.2:

let timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(UIMenuController.update), userInfo: nil, repeats: true)
  • 0
    Переименование произошло в Swift 3, и другие ответы уже сделали обновление ...

Ещё вопросы

Сообщество Overcoder
Наверх
Меню