Tra*_*ggs 2 timer grand-central-dispatch swift
这是我不久前问过的一个问题的下一章。我有这个简化的计时器,它的灵感来自于 Matt Neuburg 书中的 Timer 对象。
import Foundation
import XCPlayground
class Timer {
private var queue = dispatch_queue_create("timer", nil)
private var source: dispatch_source_t!
var tick:()->() = {}
var interval:NSTimeInterval = 1
func start() {
self.stop()
self.source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.queue)
dispatch_source_set_timer(source, DISPATCH_TIME_NOW, UInt64(self.interval) * 1000000000, 0)
dispatch_source_set_event_handler(source, self.tick)
dispatch_resume(self.source)
}
func stop() {
if self.source != nil {
dispatch_suspend(self.source)
}
}
}
var timer = Timer()
timer.interval = 5
timer.tick = { print("now \(NSDate())") }
timer.start()
timer.stop()
timer = Timer() // <<--BAD STUFF HAPPENS HERE
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
Run Code Online (Sandbox Code Playgroud)
问题在于我将新计时器分配给同一个变量。基本用例是我用完了一个计时器,所以我停止它,但随后可能想创建一个新计时器并启动它。
在操场上,该标记线给出了错误:
Execution was interrupted, reason: EXC_BAD_INSTRUCTION {code=EXC_I386_INVOP, subcode=0x0).
Run Code Online (Sandbox Code Playgroud)
如果我在 iOS 应用程序中执行类似的操作,我会得到如下所示的异常跟踪:
0: _dispatch_xref_dispose
5: MyViewController.scanTimer.setter
....
Run Code Online (Sandbox Code Playgroud)
它是结构体还是类似乎并不重要。同样的事情也会发生。我想知道我是否需要一个deinit,但我还没有找到让它消失的实现。
实际上导致代码崩溃的是当系统尝试处理事件源时。您可以start()通过使用您的类连续调用两次来看到这一点。在第二次调用期间,您将看到应用程序在尝试创建新事件源并将其分配给字段时崩溃source。
确实,如果您不调用dispatch_suspend事件源,则崩溃永远不会发生。stop()如果您在替换计时器之前注释掉对 的调用,您可以在示例中看到这一点。
我无法解释这种行为。我不知道为什么dispatch_suspend在处理事件源时调用会导致崩溃。在我看来,这就像一个错误,你应该向苹果报告。
话虽如此,您的代码中并不清楚为什么您会调用dispatch_suspend而不是dispatch_source_cancel. 当您调用stop()计时器时,您就完成了调度源。如果您再次调用start(),您无论如何都会得到一个全新的事件源。我建议将您的stop()功能更改为:
func stop() {
if self.source != nil {
dispatch_source_cancel(self.source)
self.source = nil
}
}
Run Code Online (Sandbox Code Playgroud)
这还有解决崩溃问题的额外好处。
如果您愿意接受建议,我还建议您将硬编码常量替换为调度库符号常量,表示一秒内的纳秒数:
dispatch_source_set_timer(source, DISPATCH_TIME_NOW,
UInt64(self.interval) * NSEC_PER_SEC, 0)
Run Code Online (Sandbox Code Playgroud)
我建议这样做是因为零的数量很容易出错,并且使用常量可以帮助读者理解代码实际上在做什么。
| 归档时间: |
|
| 查看次数: |
1629 次 |
| 最近记录: |