下面的代码用于在后台线程上执行长时间运行的计算:
enum CalculationInterface {
private static var latestKey: AnyObject? // Used to cancel previous calculations when a new one is initiated.
static func output(from input: Input, return: @escaping (Output?) -> ()) {
self.latestKey = EmptyObject()
let key = self.latestKey! // Made to enable capturing `self.latestKey's` value.
DispatchQueue.global().async {
do {
let output = try calculateOutput(from: input, shouldContinue: { key === self.latestKey }) // Function cancels by throwing an error.
DispatchQueue.main.async { if (key === self.latestKey) { `return`(output) } }
} catch {}
}
}
}
此函数从主线程中调用的方式如下:
/// Initiates calculation of the output and sets it to the result when finished.
private func recalculateOutput() {
self.output = .calculating // Triggers calculation in-progress animation for user.
CalculationInterface.output(from: input) { self.output = $0 } // Ends animation once set and displays calculated output to user.
}
我想知道在主线程运行我的代码时是否有可能执行被推到DispatchQueue.main
的闭包。或者换句话说,在self.output = .calculating
之后但在self.latestKey
重置为新对象之前执行。如果可以,则可以将过时的计算输出显示给用户。
不,不可能。主队列是串行队列。如果代码在主队列上运行,则不能运行“其他”主队列代码。您的DispatchQueue.main.async
有效表示:“等待直到在主队列上运行的所有代码自然结束,然后then在主队列上运行它。”
另一方面,DispatchQueue.global()
是不是串行队列。因此,从理论上讲,两个对calculateOutput
的调用可能会重叠。那不是您想发生的事情;您想确定在执行任何calculateOutput
实例之前(我们将继续处理latestKey
),然后再启动另一个实例。换句话说,您要确保序列
latestKey
calculateOutput
latestKey
连贯发生。确保此方法的方式是预留使用DispatchQueue(label:)
创建的DispatchQueue,您将始终使用它们运行calculateOutput
。默认情况下,该队列将是串行队列。