【发布时间】:2014-11-15 02:45:06
【问题描述】:
如何每分钟运行一个函数?
在 JavaScript 中我可以做类似setInterval 的事情,在 Swift 中是否存在类似的事情?
想要的输出:
Hello World 每分钟一次...
【问题讨论】:
-
为 Swift 2 更新:Swift Timer
标签: ios swift setinterval intervals repeat
如何每分钟运行一个函数?
在 JavaScript 中我可以做类似setInterval 的事情,在 Swift 中是否存在类似的事情?
想要的输出:
Hello World 每分钟一次...
【问题讨论】:
标签: ios swift setinterval intervals repeat
这是另一个版本algrid's 回答,有一个简单的方法来阻止它
@objc func executeRepeatedly() {
print("--Do something on repeat--")
perform(#selector(executeRepeatedly), with: nil, afterDelay: 60.0)
}
这是一个如何启动和停止它的示例:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
executeRepeatedly() // start it
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NSObject.cancelPreviousPerformRequests(withTarget: self) // stop it
}
【讨论】:
如果针对 iOS 10 及更高版本,您可以使用基于块的 Timer 再现,这简化了潜在的强引用周期,例如:
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()
}
虽然Timer 通常是最好的,但为了完整起见,我应该注意您还可以使用调度计时器,这对于在后台线程上调度计时器很有用。使用调度计时器,由于它们是基于块的,因此只要您使用 weak 引用,就可以避免使用旧的 target/selector 模式 Timer 带来的一些强大的引用周期挑战。
所以:
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!.schedule(deadline: .now(), repeating: .seconds(60))
timer!.setEventHandler { [weak self] in
// do whatever you want here
}
timer!.resume()
}
func stopTimer() {
timer = nil
}
有关详细信息,请参阅并发编程指南的Dispatch Sources 部分中的调度源示例的创建计时器部分。
对于 Swift 2,请参阅 previous revision of this answer。
【讨论】:
dispatch_after。或不重复的NSTimer。
你可以使用Timer (swift 3)
var timer = Timer.scheduledTimerWithTimeInterval(60, target: self, selector: Selector("function"), userInfo: nil, repeats: true)
在 selector() 中输入你的函数名
【讨论】:
Timer...NSTimer已重命名
var helloWorldTimer = NSTimer.scheduledTimerWithTimeInterval(60.0, target: self, selector: Selector("sayHello"), userInfo: nil, repeats: true)
func sayHello()
{
NSLog("hello World")
}
记得导入 Foundation。
斯威夫特 4:
var helloWorldTimer = Timer.scheduledTimer(timeInterval: 60.0, target: self, selector: #selector(ViewController.sayHello), userInfo: nil, repeats: true)
@objc func sayHello()
{
NSLog("hello World")
}
【讨论】:
NSTimer 保留它的目标,因此,使用此设置,如果 helloWorldTimer 是 self 上的一个属性,您就有了一个保留周期,其中 self保留helloWorldTimer 和helloWorldTimer 保留self。
如果您可以允许一段时间漂移,这里有一个简单的解决方案,每分钟执行一些代码:
private func executeRepeatedly() {
// put your code here
DispatchQueue.main.asyncAfter(deadline: .now() + 60.0) { [weak self] in
self?.executeRepeatedly()
}
}
只需运行一次executeRepeatedly(),它将每分钟执行一次。当拥有对象 (self) 被释放时,执行停止。您还可以使用标志来指示必须停止执行。
【讨论】:
这里是 NSTimer 答案的更新,用于 Swift 3(其中 NSTimer 被重命名为 Timer)使用闭包而不是命名函数:
var timer = Timer.scheduledTimer(withTimeInterval: 60, repeats: true) {
(_) in
print("Hello world")
}
【讨论】:
在 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()
当您需要在特定队列上调度时,这特别有用。另外,如果您打算使用它来更新用户界面,我建议您查看CADisplayLink,因为它与 GPU 刷新率同步。
【讨论】: