在 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 保留它的目标,因此,使用此设置,如果 helloWorldTimerself 上的一个属性,您就有了一个保留周期,其中 self保留helloWorldTimerhelloWorldTimer 保留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 分钟做一次的主要内容,如果未能解决你的问题,请参考以下文章

在Swift 2.0中每隔n分钟更新一次背景中的位置

如何在无限循环中每 3 分钟回显一次?

在日期时间中每 10 分钟绘制一次

在 Flutter 中每 1 分钟发出一次定时 http.get 请求的最简单方法是啥?

如何在 iOS 应用程序中每 n 分钟获取一次后台位置更新?

在 do while 循环内部,我想在 c# 中每 1 分钟执行一次特定代码,直到条件满足