恰当的数据结构,能让代码产生质的飞跃。本篇总结下在开发中对‘队列’的一点体会。
有限资源的访问
先进先出(FIFO)是队列的本质属性,所以当遇到这样的需求时,比如实现一个FIFO的cache,那么使用队列自然不需要太多思考。
本篇主要总结下在App中使用队列来控制对‘有限的资源’的访问。
队列在iOS框架中随处可见,比如主线程的runloop会把所有等待处理的Event放在队列里,GCD的serial queue本身就是一个队列,还有NSOperationQueue等。这些例子中有一个共同的模式,就是对一个有限资源的使用,runloop是资源,线程是资源。
而在多线程编程中,我们常常使用锁来控制对资源的访问。从某种角度来看,锁也是操作系统提供的存放访问线程的队列。
道理很简单,更多的时候需要思考的是:什么是有限的资源,什么是资源的访问者。
举一个例子:在iOS中,弹窗(alert view)最多只能显示一个,比如定位城市更新、订单状态改变等。于是我们使用了队列来控制对弹窗的使用(swift伪代码,省略了一些细节):
public class WindowManager {
private var _queue: Queue<(String, String)>
private var isShowing: Bool
public func show(title: String, message: String) {
onMainQueue {
if isShowing {
_queue.enqueue((title, message))
} else {
showInternal(title, message)
}
}
}
public func dismiss() {
onMainQueue {
dismissInternal()
// schedule pending windows
if _queue is not empty {
let (title, message) = _queue.dequeue()
showInternal(title, message)
}
}
}
private func showInternal(title: String, message: String) {
isShowing = true
showAlertView()
}
private func dismissInternal() {
isShowing = false
dismissAlertView()
}
// execute block on main queue
private func onMainQueue(block: () -> Void) {
if NSThread.isMainThread() {
block()
} else {
dispatch_async(dispatch_get_main_queue(), block)
}
}
}
后来需求变复杂了些,比如当前在登录界面时,弹窗需要等登录界面退出再显示。