在 Swift 中每 x 分钟做一次
Posted
技术标签:
【中文标题】在 Swift 中每 x 分钟做一次【英文标题】:Do something every x minutes in Swift 【发布时间】:2014-11-15 02:45:06 【问题描述】:如何每分钟运行一个函数?
在 javascript 中我可以做类似setInterval
的事情,在 Swift 中是否存在类似的事情?
想要的输出:
Hello World 每分钟一次...
【问题讨论】:
为 Swift 2 更新:Swift Timer 【参考方案1】:这是另一个版本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
【讨论】:
【参考方案2】:如果针对 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。
【讨论】:
在这种方法中你会如何使用只执行一次的计时器? @JuanPabloBoero - 我不会将这种方法用于一次性的情况。你会使用dispatch_after
。或不重复的NSTimer
。
@Rob 我在屏幕上有一个计数器标签,它每秒都会从一个函数中更新,我正在使用上面的代码来增加我的计数器并更新标签文本。但是,我面临的问题是我的计数器变量每秒更新一次,但屏幕没有在我的 UILabel 中显示最新的计数器值。
Rao,以上对于在后台线程上执行某些操作很有用。但是您的 UI 更新必须发生在主队列上。因此,要么将其安排在主线程上,要么至少将 UI 更新分派回主线程。
这个问题在 cmets 中不属于这个答案。删除上面的 cmets 并发布您自己的问题。但是,简而言之,您通常不会真正让应用程序在后台运行,而只是让它看起来像原来那样。见***.com/a/31642036/1271826。【参考方案3】:
你可以使用Timer
(swift 3)
var timer = Timer.scheduledTimerWithTimeInterval(60, target: self, selector: Selector("function"), userInfo: nil, repeats: true)
在 selector() 中输入你的函数名
【讨论】:
如何在 swift 3 中做到这一点? 使用Timer
...NSTimer
已重命名【参考方案4】:
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")
【讨论】:
但是如果你想在视图之间切换呢?代码会停止吧? @Cing 取决于 self 指的是什么。 不要忘记NSTimer
保留它的目标,因此,使用此设置,如果 helloWorldTimer
是 self
上的一个属性,您就有了一个保留周期,其中 self
保留helloWorldTimer
和helloWorldTimer
保留self
。
@MANIAK_dobrii 你能否评论一下如何打破保留周期?如果 VC 被解散但计时器没有被取消,那么循环是否仍然有效?所以你必须取消计时器然后关闭视图才能打破循环?
对于 Swift 4,要获取选择器的方法必须暴露给 Objective-C,因此必须在方法声明中添加 @objc 属性。例如 ``` @objc func sayHello() ```【参考方案5】:
如果您可以允许一段时间漂移,这里有一个简单的解决方案,每分钟执行一些代码:
private func executeRepeatedly()
// put your code here
DispatchQueue.main.asyncAfter(deadline: .now() + 60.0) [weak self] in
self?.executeRepeatedly()
只需运行一次executeRepeatedly()
,它将每分钟执行一次。当拥有对象 (self
) 被释放时,执行停止。您还可以使用标志来指示必须停止执行。
【讨论】:
这个决定比围绕所有这些计时器更方便,将它们添加到运行循环中,使它们无效......酷! 这似乎是有效的解决方案,但是当我将它与我的 Web 服务调用一起使用时,它会创建一个保留周期......【参考方案6】:这里是 NSTimer
答案的更新,用于 Swift 3(其中 NSTimer
被重命名为 Timer
)使用闭包而不是命名函数:
var timer = Timer.scheduledTimer(withTimeInterval: 60, repeats: true)
(_) in
print("Hello world")
【讨论】:
这仅适用于 iOS 10。 请不要发布ios 10+解决方案【参考方案7】:在 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 刷新率同步。
【讨论】:
以上是关于在 Swift 中每 x 分钟做一次的主要内容,如果未能解决你的问题,请参考以下文章
在 Flutter 中每 1 分钟发出一次定时 http.get 请求的最简单方法是啥?