swift - 杀死并重新运行后台计时器(DispatchSourceTimer)
问题描述
在游戏屏幕中,我使用后台队列来计算游戏中经过的时间,这个函数基于Daniel Galasko 解决方案,这是我的应用程序的完美解决方案:它允许用户在计时器仍然打开的情况下浏览其他 VC。VC 层次结构非常简单:游戏设置 VC 在 tabBarController 中处理。游戏画面是分开的。用户可以在定时器开启时更改设置。设置存储在 CoreData 中。
在我需要显示计时器的游戏屏幕中,我有一个显示经过时间的标签和 2 个按钮:播放/暂停按钮和重置按钮。
我在 ViewDidLoad 中调用我的设置计时器函数。我的计时器的默认值是存储在 CoreData 中的值,它已在设置中定义。当定时器开启时,该值每秒增加 1。我也有一个静态的让共享保持计时器状态(恢复/暂停)。
当我在游戏屏幕上时,如果我的计时器被暂停,我的播放/暂停按钮可以完美运行:我可以导航到其他视图(意味着关闭我的屏幕游戏),再次展示我的屏幕游戏并恢复我的计数器。它正确更新了我的标签。
问题是当我在计时器运行时关闭游戏屏幕视图时。定时器工作(打印功能显示定时器仍在运行),但是当我再次显示屏幕时,我无法暂停/恢复/重新启动它,并且我的标签在我回来的第二秒停止......而定时器是还在往回跑。
private var counter: Int16?
var t = RepeatingTimer(timeInterval: 1)
let gameIsOn = isGameOnManager.shared
override func viewDidLoad() {
super.viewDidLoad()
print("is timer On ? \(String(describing: gameIsOn.isgameOn))")
buildTimer()
if gameIsOn.isgameOn == true {
resumeTapped = true
t.resume()
PlayB.setImage(UIImage(named:"pause"), for: .normal)
} else {
resumeTapped = false
}
}
func buildTimer(){
self.t.eventHandler = {
self.counter! += 1
print("counter \(String(describing: self.counter!))")
self.coreDataEntity?.TimeAttribute = self.counter ?? 0
self.save()
DispatchQueue.main.async {
self.dataField.text = String(describing: self.counter ?? 0)
}
}
}
@objc func didTapButton(_ button: UIButton) {
if resumeTapped == false {
t.resume()
resumeTapped = true
gameIsOn.isgameOn = true
PlayB.setImage(UIImage(named:"pause"), for: .normal)
}
else if resumeTapped == true {
t.suspend()
resumeTapped = false
gameIsOn.isgameOn = false
PlayB.setImage(UIImage(named:"play"), for: .normal)
}
}
解决方案
您的视图控制器、计时器和计时器的事件处理程序之间有一个强引用循环。您应该在闭包中使用weak
引用来打破这个循环:
func buildTimer() {
t.eventHandler = { [weak self] in
guard let self = self else { return }
...
}
}
这修复了强参考周期。
但是当你解决这个问题时,当你关闭这个视图控制器时,你可能会看到你的计时器停止运行。如果是这种情况,则表明计时器不在正确的对象中。它应该在整个应用程序中持续存在的一些更高级别的对象中,而不是在呈现和关闭的视图控制器中。
推荐阅读
- selenium - 如何禁用“始终在相关应用中打开这些类型的链接”Chrome 警报
- emoji - 如何通过 Onesignal 中的 api 发送表情符号
- java - 如何使用 quarkus 创建本机可执行文件?
- javascript - javascript 代码的某些部分使 chrome 在 Ios 中挂起
- c# - 带有 Postgres 的实体框架导致“其他用户正在访问数据库”
- wordpress - 如何使用表格开发一种联系表格,但删除移动设备的表格?
- reactjs - 反应路由器确切路径
- android - 如何在列表视图中获取项目的坐标?
- mysql - 具有 SQL 模式的 MySQL BETWEEN 运算符
- java - 如何理解 AQS 上的“isOnSyncQueue”功能