ProcedureKit(基于NSOperation
)是现成解决方案的一个示例,但仅将其用于动画是相当重量级的。
我Operation
用来排队动画弹出窗口和其他东西的子类:
class SerialAsyncOperation: Operation {
private var _started = false
private var _finished = false {
willSet {
guard _started, newValue != _finished else {
return
}
willChangeValue(forKey: "isFinished")
}
didSet {
guard _started, oldValue != _finished else {
return
}
didChangeValue(forKey: "isFinished")
}
}
private var _executing = false {
willSet {
guard newValue != _executing else {
return
}
willChangeValue(forKey: "isExecuting")
}
didSet {
guard oldValue != _executing else {
return
}
didChangeValue(forKey: "isExecuting")
}
}
override var isAsynchronous: Bool {
return true
}
override var isFinished: Bool {
return _finished
}
override var isExecuting: Bool {
return _executing
}
override func start() {
guard !isCancelled else {
return
}
_executing = true
_started = true
main()
}
func finish() {
_executing = false
_finished = true
}
override func cancel() {
_executing = false
_finished = true
super.cancel()
}
}
使用示例:
// Setup a serial queue
private lazy var serialQueue: OperationQueue = {
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
queue.name = String(describing: type(of: self))
return queue
}()
// subclass SerialAsyncOperation
private class MessageOperation: SerialAsyncOperation {
// ...
override func main() {
DispatchQueue.main.async { [weak self] in
// do UI stuff
self?.present(completion: {
self?.finish()
})
}
}
func present(completion: @escaping () -> Void) {
// do async animated presentation, calling completion() in its completion
}
func dismiss(completion: @escaping () -> Void) {
// do async animated dismissal, calling completion() in its completion
}
// animated cancellation support
override func cancel() {
if isExecuting {
dismiss(completion: {
super.cancel()
})
} else {
super.cancel()
}
}
}
finish()
基本上,只需将此操作添加到串行队列中,并记住在完成异步操作时调用。您还可以通过一次调用取消串行队列上的所有操作,这些操作将被优雅地解除。