Як я можу використовувати таймер (раніше NSTimer) у Swift?


257

я намагався

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 не змінився.
Парамагнітний круасан

Відповіді:


534

Це спрацює:

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, метод якого потрібно отримати селектором, повинен піддаватися об’єкту-C, таким чином @objcатрибут повинен бути доданий до декларації методу.


2
Додам, що клас з цими методами повинен бути NSObject, інакше ви виявите невпізнанну помилку селектора
Джошуа

27
Станом на Xcode 6.1, я повинен був додати "@objc" до заголовка функції так: "@objc func update () {". Без цього додаток виходить з ладу при першому пожежі.
кев

Ви можете оголосити таймер Var: NSTimer! спочатку і використовуйте його коли потрібно!
Нігілан

1
Можливо, більш корисна версія синтаксису блоків: нехай таймер = Timer.scheduledTimer (withTimeInterval: timeout, повтори: false) {_ in print ("Готово")}
Teo

Ви не можете використовувати 'let timer = Timer (timeInterval: 0.4, повторення: true) {_ in print («Готово!»)}', Цей таймер не запуститься, і ви не зможете його повторити. Ви повинні використовувати Timer.scheduledTimer.
Сіамастер

149

Повторна подія

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

введіть тут опис зображення

Ось код для цього:

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()якщо вам потрібно скасувати подію, перш ніж вона відбудеться.

Примітки

  • Якщо є шанс запустити свій примірник таймера кілька разів, переконайтеся, що ви попередньо визнали недійсним попередній екземпляр таймера. Інакше ви втрачаєте посилання на таймер і більше не можете його зупинити. (див. це питання та відповіді )
  • Не використовуйте таймери, коли вони не потрібні. Дивіться розділ таймерів Посібника з енергоефективності для iOS Apps .

Пов'язані


1
@raddevus, дякую, що повідомили мені. Я видалив старий коментар Swift 3.
Сурагч

31

Оновлено до Swift 4, використовуючи користувачInfo:

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
Покажіть робочий приклад, що означають "користувацькі" та "дані", якщо функція очікує NSTimerоб'єкт
Carlos.V

1
Це насправді не має значення. Ви можете зберігати все необхідне у словнику userInfo, в цьому випадку це довільна пара ключ-значення.
igraczech

Це корисно, але зламано у Swift 3, робочий приклад: Timer.scheduledTimer (timeInterval: 1.0, target: self, selector: #selector (подія), userInfo: "Інформація надіслана", повторюється: true)
Боббі

28

Станом на iOS 10 є також новий заводський метод таймеру на основі блоку, який є більш чистим, ніж використання селектора:

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

1
Як ви це робите, чи не було б краще просто зняти _ = і почати з цього Timer?
Мед

2
Ви можете опустити _ = якщо ви замовкли попередження про невикористане значення або якщо вам просто не цікаво попередження. Мені не подобається перевіряти код з попередженнями.
Джош Гоман

22

Швидкий 3, попередній 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, повторення: false) {timer in DispatchQueue.main.async {print (таймер)}}
Матьє Фрінетт

Мій таймер не спрацьовував з одного з моїх об’єктів, і це зробило хитрість :)
Реймонд Хілл

@ReimondHill Вам потрібно змінитиtimeInterval
onmyway133

17

Перевірте:

Швидкий 2

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

Швидкий 3, 4, 5

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

2
Я вже спробував це, але там написано: "Не вдалося знайти перевантаження для" init ", який приймає надані аргументи"
user3225917

1
Тут же я отримав помилку "Не вдалося знайти перевантаження для" init ", яка приймає надані аргументи". Чи справді ця лінія працює?
Yangshun Tay

Я отримую ту ж помилку, що і @yangshun. Який тип об’єкта повинен selfбути? UIView в порядку?
SimplGy

@SimpleAsCouldBe: так, це нормально
Мідхун MP

func iznosSubmitSuccess () {self.view.hideToastActivity () self.view.makeToast (повідомлення: "Сума успішно зареєстрована") var timer = NSTimer.scheduledTimerWithTimeInterval (0,5, ціль: self, селектор: "moveToBidderPage", користувачInfo: повторює: false)} func moveToBidderPage () {хай loginPageView = self.storyboard? .instantiateViewControllerWithIdentifier ("bidderpageID") як! BidderPage self.navigationController? .PushViewController (loginPageView, анімований: правда)}
AG

11

Вам потрібно буде використовувати Timer замість 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
}

11

Швидкий 5

Я особисто віддаю перевагу таймеру з блокуванням блоку:

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

Пам’ятайте, що це доступно лише в macOS 10.12 або новіших версіях. Не впевнений у ios.
jeff-h

Він доступний і в iOS.
Вісса

7

для swift 3 та Xcode 8.2 (приємно мати блоки, але якщо ви компілюєте для iOS9 AND хочете 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)
    }

6

SimpleTimer (Swift 3.1)

Чому?

Це простий клас таймера в швидкому режимі, який дозволяє вам:

  • Місцевий масштабний таймер
  • Можливий
  • Один лайнер
  • Використовуйте регулярні зворотні дзвінки

Використання:

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

Як тоді зупинити таймер всередині цього блоку на деяких умовах?
Mobile Developer iOS Android

Просто зберігайте посилання на таймер у класі, а потім просто зупиніть дзвінок. Компілятор xcode підкаже, чи потрібен він втечу тощо
eonist

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

І створюйте задоволення від імені createEnemy

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

3

Спочатку оголосіть свій таймер

var timer: Timer?

Потім додайте рядок у viewDidLoad () або в будь-яку функцію, яку ви хочете запустити таймер

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

Це функція, яку ви будете відкликати, щоб зробити щось, що має бути @objc

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

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

Якщо ви init метод таймера

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

Я спробував зробити в NSObject Class, і це спрацювало для мене:

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

-2

NSTimer було перейменовано на Timer у Swift 4.2. цей синтаксис буде працювати в 4.2:

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

Перейменування відбулося в Swift 3, а інші відповіді вже виконали оновлення ...
Ерік Айя
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.