在Swift中每隔x分钟做一些事情

时间:2021-11-04 04:02:00

How can I run a function every minute?In JavaScript I can do something like setInterval, does something similar exist in Swift?

我怎样才能每分钟运行一个函数?在JavaScript中我可以做类似setInterval的事情,在Swift中是否存在类似的东西?

Wanted output:

Hello World once a minute...

你好世界每分钟一次......

6 个解决方案

#1


137  

var helloWorldTimer = NSTimer.scheduledTimerWithTimeInterval(60.0, target: self, selector: Selector("sayHello"), userInfo: nil, repeats: true)func sayHello() {    NSLog("hello World")}

Remember to import Foundation.

记得导入Foundation。

Swift 4:

 var helloWorldTimer = Timer.scheduledTimer(timeInterval: 60.0, target: self, selector: #selector(ViewController.sayHello), userInfo: nil, repeats: true) @objc func sayHello()  {     NSLog("hello World") }

#2


113  

In Swift 3, you can create a Timer. And if targeting iOS version 10 and greater, you can use the block-based rendition, which simplifies the potential strong reference cycles, e.g.:

在Swift 3中,您可以创建一个Timer。如果针对iOS 10及更高版本,您可以使用基于块的再现,这简化了潜在的强引用周期,例如:

weak var timer: Timer?func startTimer() {    timer?.invalidate()   // just in case you had existing `Timer`, `invalidate` it before we lose our reference to it    timer = Timer.scheduledTimer(withTimeInterval: 60.0, repeats: true) { [weak self] _ in        // do something here    }}func stopTimer() {    timer?.invalidate()}// if appropriate, make sure to stop your timer in `deinit`deinit {    stopTimer()}

In Swift 2, you create a NSTimer. And if you're using Swift 2, you may well be using iOS version prior to 10.0, in which case you have to use the older target/selector pattern:

在Swift 2中,您创建了一个NSTimer。如果你使用的是Swift 2,你很可能会使用10.0之前的iOS版本,在这种情况下你必须使用旧的目标/选择器模式:

weak var timer: NSTimer?func startTimer() {    timer?.invalidate()   // just in case you had existing `NSTimer`, `invalidate` it before we lose our reference to it    timer = NSTimer.scheduledTimerWithTimeInterval(60.0, target: self, selector: #selector(handleTimer(_:)), userInfo: nil, repeats: true)}func handleTimer(timer: NSTimer) {    // do something here}func stopTimer() {    timer?.invalidate()}// because this old target/selector approach will keep a strong reference// to the `target`, if you want the timer to stop when the view controller// is dismissed, you can't stop the timer in `deinit`, but rather have to // detect the dismissing of the view controller using other mechanisms. Commonly,// we used to detect the view disappearing, like below:override func viewDidDisappear(animated: Bool) {    super.viewDidDisappear(animated)    stopTimer()}

While NSTimer is generally best, for the sake of completeness, I should note that you can also use dispatch timer, which is useful for scheduling timers on background threads. With dispatch timers, since they're block-based, it avoids some of the strong reference cycle challenges with the old target/selector pattern of NSTimer, as long as you use weak references.

虽然NSTimer通常是最好的,但为了完整起见,我应该注意你也可以使用dispatch timer,这对于在后台线程上调度定时器很有用。使用调度计时器,因为它们是基于块的,所以只要您使用弱引用,它就可以避免使用NSTimer的旧目标/选择器模式的一些强大的参考周期挑战。

So, in Swift 3:

所以,在Swift 3中:

var timer: DispatchSourceTimer?func startTimer() {    let queue = DispatchQueue(label: "com.domain.app.timer")  // you can also use `DispatchQueue.main`, if you want    timer = DispatchSource.makeTimerSource(queue: queue)    timer!.scheduleRepeating(deadline: .now(), interval: .seconds(60))    timer!.setEventHandler { [weak self] in        // do whatever you want here    }    timer!.resume()}func stopTimer() {    timer?.cancel()    timer = nil}deinit {    self.stopTimer()}

In Swift 2:

在Swift 2中:

var timer: dispatch_source_t?func startTimer() {    let queue = dispatch_queue_create("com.domain.app.timer", nil) // again, you can use `dispatch_get_main_queue()` if you want to use the main queue    timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue)    dispatch_source_set_timer(timer!, DISPATCH_TIME_NOW, 60 * NSEC_PER_SEC, 1 * NSEC_PER_SEC) // every 60 seconds, with leeway of 1 second    dispatch_source_set_event_handler(timer!) { [weak self] in        // do whatever you want here    }    dispatch_resume(timer!)}func stopTimer() {    if let timer = timer {        dispatch_source_cancel(timer)        self.timer = nil    }}deinit {    self.stopTimer()}

For more information, see the the Creating a Timer section of Dispatch Source Examples in the Dispatch Sources section of the Concurrency Programming Guide.

有关更多信息,请参阅“并发编程指南”的“Dispatch Sources”部分中的“Dispatch Source Examples”的“Creating a Timer”部分。

#3


14  

Here's an update to the NSTimer answer, for Swift 3 (in which NSTimer was renamed to Timer) using a closure rather than a named function:

这是对使用闭包而不是命名函数的Swift 3(其中NSTimer被重命名为Timer)的NSTimer答案的更新:

var timer = Timer.scheduledTimer(withTimeInterval: 60, repeats: true) {    (_) in    print("Hello world")}

#4


11  

You can use NSTimer

您可以使用NSTimer

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

In selector() you put in your function name

在selector()中输入你的函数名

#5


7  

In swift 3.0 the GCD got refactored:

在swift 3.0中,GCD被重构:

let timer : DispatchSourceTimer = DispatchSource.makeTimerSource(flags: [], queue: DispatchQueue.main)timer.scheduleRepeating(deadline: .now(), interval: .seconds(60))timer.setEventHandler{    NSLog("Hello World")}timer.resume()

This is specially useful for when you need to dispatch on a particular Queue. Also, if you're planning on using this for user interface updating, I suggest looking into CADisplayLink as it's synchronized with the GPU refresh rate.

当您需要在特定队列上调度时,这特别有用。此外,如果您计划将其用于用户界面更新,我建议您查看CADisplayLink,因为它与GPU刷新率同步。

#6


2  

If you can allow for some time drift here's a simple solution executing some code every minute:

如果你可以允许一段时间漂移,这是一个简单的解决方案,每分钟执行一些代码:

private func executeRepeatedly() {    // put your code here    DispatchQueue.main.asyncAfter(deadline: .now() + 60.0) { [weak self] in        self?.executeRepeatedly()    }}

Just run executeRepeatedly() once and it'll be executed every minute. The execution stops when the owning object (self) is released. You also can use a flag to indicate that the execution must stop.

只需运行executeRepeatedly()一次,它就会每分钟执行一次。释放拥有对象(self)时执行停止。您还可以使用标志来指示执行必须停止。

#1


137  

var helloWorldTimer = NSTimer.scheduledTimerWithTimeInterval(60.0, target: self, selector: Selector("sayHello"), userInfo: nil, repeats: true)func sayHello() {    NSLog("hello World")}

Remember to import Foundation.

记得导入Foundation。

Swift 4:

 var helloWorldTimer = Timer.scheduledTimer(timeInterval: 60.0, target: self, selector: #selector(ViewController.sayHello), userInfo: nil, repeats: true) @objc func sayHello()  {     NSLog("hello World") }

#2


113  

In Swift 3, you can create a Timer. And if targeting iOS version 10 and greater, you can use the block-based rendition, which simplifies the potential strong reference cycles, e.g.:

在Swift 3中,您可以创建一个Timer。如果针对iOS 10及更高版本,您可以使用基于块的再现,这简化了潜在的强引用周期,例如:

weak var timer: Timer?func startTimer() {    timer?.invalidate()   // just in case you had existing `Timer`, `invalidate` it before we lose our reference to it    timer = Timer.scheduledTimer(withTimeInterval: 60.0, repeats: true) { [weak self] _ in        // do something here    }}func stopTimer() {    timer?.invalidate()}// if appropriate, make sure to stop your timer in `deinit`deinit {    stopTimer()}

In Swift 2, you create a NSTimer. And if you're using Swift 2, you may well be using iOS version prior to 10.0, in which case you have to use the older target/selector pattern:

在Swift 2中,您创建了一个NSTimer。如果你使用的是Swift 2,你很可能会使用10.0之前的iOS版本,在这种情况下你必须使用旧的目标/选择器模式:

weak var timer: NSTimer?func startTimer() {    timer?.invalidate()   // just in case you had existing `NSTimer`, `invalidate` it before we lose our reference to it    timer = NSTimer.scheduledTimerWithTimeInterval(60.0, target: self, selector: #selector(handleTimer(_:)), userInfo: nil, repeats: true)}func handleTimer(timer: NSTimer) {    // do something here}func stopTimer() {    timer?.invalidate()}// because this old target/selector approach will keep a strong reference// to the `target`, if you want the timer to stop when the view controller// is dismissed, you can't stop the timer in `deinit`, but rather have to // detect the dismissing of the view controller using other mechanisms. Commonly,// we used to detect the view disappearing, like below:override func viewDidDisappear(animated: Bool) {    super.viewDidDisappear(animated)    stopTimer()}

While NSTimer is generally best, for the sake of completeness, I should note that you can also use dispatch timer, which is useful for scheduling timers on background threads. With dispatch timers, since they're block-based, it avoids some of the strong reference cycle challenges with the old target/selector pattern of NSTimer, as long as you use weak references.

虽然NSTimer通常是最好的,但为了完整起见,我应该注意你也可以使用dispatch timer,这对于在后台线程上调度定时器很有用。使用调度计时器,因为它们是基于块的,所以只要您使用弱引用,它就可以避免使用NSTimer的旧目标/选择器模式的一些强大的参考周期挑战。

So, in Swift 3:

所以,在Swift 3中:

var timer: DispatchSourceTimer?func startTimer() {    let queue = DispatchQueue(label: "com.domain.app.timer")  // you can also use `DispatchQueue.main`, if you want    timer = DispatchSource.makeTimerSource(queue: queue)    timer!.scheduleRepeating(deadline: .now(), interval: .seconds(60))    timer!.setEventHandler { [weak self] in        // do whatever you want here    }    timer!.resume()}func stopTimer() {    timer?.cancel()    timer = nil}deinit {    self.stopTimer()}

In Swift 2:

在Swift 2中:

var timer: dispatch_source_t?func startTimer() {    let queue = dispatch_queue_create("com.domain.app.timer", nil) // again, you can use `dispatch_get_main_queue()` if you want to use the main queue    timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue)    dispatch_source_set_timer(timer!, DISPATCH_TIME_NOW, 60 * NSEC_PER_SEC, 1 * NSEC_PER_SEC) // every 60 seconds, with leeway of 1 second    dispatch_source_set_event_handler(timer!) { [weak self] in        // do whatever you want here    }    dispatch_resume(timer!)}func stopTimer() {    if let timer = timer {        dispatch_source_cancel(timer)        self.timer = nil    }}deinit {    self.stopTimer()}

For more information, see the the Creating a Timer section of Dispatch Source Examples in the Dispatch Sources section of the Concurrency Programming Guide.

有关更多信息,请参阅“并发编程指南”的“Dispatch Sources”部分中的“Dispatch Source Examples”的“Creating a Timer”部分。

#3


14  

Here's an update to the NSTimer answer, for Swift 3 (in which NSTimer was renamed to Timer) using a closure rather than a named function:

这是对使用闭包而不是命名函数的Swift 3(其中NSTimer被重命名为Timer)的NSTimer答案的更新:

var timer = Timer.scheduledTimer(withTimeInterval: 60, repeats: true) {    (_) in    print("Hello world")}

#4


11  

You can use NSTimer

您可以使用NSTimer

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

In selector() you put in your function name

在selector()中输入你的函数名

#5


7  

In swift 3.0 the GCD got refactored:

在swift 3.0中,GCD被重构:

let timer : DispatchSourceTimer = DispatchSource.makeTimerSource(flags: [], queue: DispatchQueue.main)timer.scheduleRepeating(deadline: .now(), interval: .seconds(60))timer.setEventHandler{    NSLog("Hello World")}timer.resume()

This is specially useful for when you need to dispatch on a particular Queue. Also, if you're planning on using this for user interface updating, I suggest looking into CADisplayLink as it's synchronized with the GPU refresh rate.

当您需要在特定队列上调度时,这特别有用。此外,如果您计划将其用于用户界面更新,我建议您查看CADisplayLink,因为它与GPU刷新率同步。

#6


2  

If you can allow for some time drift here's a simple solution executing some code every minute:

如果你可以允许一段时间漂移,这是一个简单的解决方案,每分钟执行一些代码:

private func executeRepeatedly() {    // put your code here    DispatchQueue.main.asyncAfter(deadline: .now() + 60.0) { [weak self] in        self?.executeRepeatedly()    }}

Just run executeRepeatedly() once and it'll be executed every minute. The execution stops when the owning object (self) is released. You also can use a flag to indicate that the execution must stop.

只需运行executeRepeatedly()一次,它就会每分钟执行一次。释放拥有对象(self)时执行停止。您还可以使用标志来指示执行必须停止。