如何在Swift中使用Timer(以前称为NSTimer)?


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
“如何在Swift中使用NSTimer?” –与在Objective-C中使用它的方式相同。其API不变。
顺磁牛角包

Answers:


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,要获取选择器的方法必须公开给Objective-C,因此@objc必须将属性添加到方法声明中。


2
我要补充说,使用这些方法的类必须是NSObject,否则您将遇到无法识别的选择器错误
Joshua

27
从Xcode 6.1开始,我必须将“ @objc”添加到函数标头中,例如:“ @ objc func update(){”。没有它,应用程序将在第一次火灾时崩溃。
2014年

您可以声明Var计时器:NSTimer!最初,并在需要时使用它!
Nigilan

1
块语法的一个可能更有用的版本:let timer = Timer.scheduledTimer(withTimeInterval:timeout,重复:false){_ in print(“ Done。”)}}
Teo Sartori,

您不能使用'let timer = Timer(timeInterval:0.4,repeats:true){_ in print(“ Done!”)}',这将不会启动计时器,因此您无法使其重复。您必须使用Timer.scheduledTimer。
Siamaster

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应用能源效率指南》中的计时器部分。

有关


1
@raddevus,谢谢让我知道。我删除了旧的Swift 3评论。
Suragch

31

更新至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
显示一个工作示例,如果函数期望NSTimer对象,则“ custom”和“ data”是什么意思
Carlos.V

1
真的没关系。您可以自由地将所需的任何内容存储在userInfo字典中,在这种情况下,它是任意键/值对。
igraczech '17

这很有用,但是在Swift 3中却无法使用,它是一个工作示例:Timer.scheduledTimer(timeInterval:1.0,target:self,选择器:#selector(event),userInfo:“ Info Sent”,重复:true)
Bobby

28

从iOS 10开始,还有一个新的基于块的Timer工厂方法,该方法比使用选择器更干净:

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

1
您这样做的方式,仅删除_ = 并从头开始会更好Timer吗?
亲爱的

2
如果您将有关未使用值的警告静音,或者只是不关心警告,则可以省略_ =。我不喜欢在带有警告的情况下检入代码。
乔什·霍曼

22

iOS 10之前的Swift 3

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){DispatchQueue.main.async中的计时器{打印(timer)}}
Mathieu Frenette

我的计时器不是从我的对象之一触发的,而是成功的方法:)
Reimond Hill,

@ReimondHill您需要更改timeInterval
onmyway133'8

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接受提供的参数的
重载

1
同样在这里,我得到了错误“无法为接受提供的参数的'init'找到重载”。这条线真的有效吗?
Yangshun Tay 2014年

我收到与@yangshun相同的错误。什么类型的对象必须self是?UIView可以吗?
SimplGy 2014年

@SimpleAsCouldBe:是的,没关系
Midhun MP

func amountSubmitSuccess(){self.view.hideToastActivity()self.view.makeToast(message:“ Amount Successed”)var timer = NSTimer.scheduledTimerWithTimeInterval(0.5,target:self,选择器:“ moveToBidderPage”,userInfo:无,重复:false)} func moveToBidderPage(){让loginPageView = self.storyboard?.instantiateViewControllerWithIdentifier(“ bidderpageID”)为!BidderPage self.navigationController?.pushViewController(loginPageView,animation:true)}
AG

11

在Swift 3中,您将需要使用Timer而不是NSTimer。

这是一个例子:

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:

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

请注意,这仅在macOS 10.12或更高版本中可用。不确定ios。
jeff-h

它也可以在iOS中使用。
瓦萨(Wissa)

7

对于swift 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)
    }

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

只需将引用存储到计时器中的类中,然后调用stop即可。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

如果您初始化计时器的方法

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)

注意:如果您希望重复此操作,请使true重复并保持计时器的引用,否则将不会调用update方法。

如果您正在使用此方法。

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

如果重复为true,请保留参考以供以后使用。


0

我尝试在NSObject类中这样做,这对我有用:

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

-2

NSTimer在Swift 4.2中已重命名为Timer。此语法将在4.2中工作:

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

重命名发生在Swift 3中,其他答案已经完成了更新...
Eric Aya
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.