用Swift每隔x分钟做点什么

时间:2021-10-04 01:08:29

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


123  

var helloWorldTimer = NSTimer.scheduledTimerWithTimeInterval(60.0, target: self, selector: Selector("sayHello"), userInfo: nil, repeats: true)

func sayHello() 
{
    NSLog("hello World")
}

Remember to import Foundation.

记得要导入的基础。

Swift 3:

斯威夫特3:

 var helloWorldTimer = Timer.scheduledTimer(timeInterval: 60.0, target: self, selector: #selector(ViewController.sayHello), userInfo: nil, repeats: true)

 func sayHello() 
 {
     NSLog("hello World")
 }

#2


111  

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中,您可以创建一个计时器。如果针对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:

所以,在迅速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:

在斯威夫特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.

有关更多信息,请参阅在并发编程指南的分派源部分创建调度源示例的计时器部分。

#3


13  

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:

下面是对NSTimer答案的更新,对于Swift 3 (NSTimer被重命名为Timer)使用闭包而不是命名函数:

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

#4


10  

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

在选择器()中放入函数名。

#5


5  

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


0  

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.

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

#1


123  

var helloWorldTimer = NSTimer.scheduledTimerWithTimeInterval(60.0, target: self, selector: Selector("sayHello"), userInfo: nil, repeats: true)

func sayHello() 
{
    NSLog("hello World")
}

Remember to import Foundation.

记得要导入的基础。

Swift 3:

斯威夫特3:

 var helloWorldTimer = Timer.scheduledTimer(timeInterval: 60.0, target: self, selector: #selector(ViewController.sayHello), userInfo: nil, repeats: true)

 func sayHello() 
 {
     NSLog("hello World")
 }

#2


111  

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中,您可以创建一个计时器。如果针对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:

所以,在迅速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:

在斯威夫特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.

有关更多信息,请参阅在并发编程指南的分派源部分创建调度源示例的计时器部分。

#3


13  

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:

下面是对NSTimer答案的更新,对于Swift 3 (NSTimer被重命名为Timer)使用闭包而不是命名函数:

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

#4


10  

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

在选择器()中放入函数名。

#5


5  

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


0  

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.

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