前言
本文代码虽是手动code了一遍并小小做了改动,但是终究是在他人demo的基础上编排出的,即便是个比较简单的例子,但是这个..那个..为了尊重别人劳动成果,还是分类到了转载,这里特别感谢一下@非典型技术宅老兄的原文,想必大家都听腻了太多的多线程的概念理论,本文不大书理论,用实例讲述Operation Queues 的用法,就是这么任性!
并行执行任务,全部完成后刷新UI
需求:
2.下载过程中显示loading
3.全部下载完成后停止loading
代码:
let imgW = Int(UIScreen.main.bounds.width - 20) let imgH = Int((UIScreen.main.bounds.height - 80)/4) @IBOutlet weak var indicator: UIActivityIndicatorView! @IBOutlet weak var img1: UIImageView! @IBOutlet weak var img2: UIImageView! @IBOutlet weak var img3: UIImageView! @IBOutlet weak var img4: UIImageView! let operationQueue = OperationQueue() var imageViews: [UIImageView]? var operationType: OperationType? override func viewDidLoad() { super.viewDidLoad() imageViews = [img1,img2,img3,img4] } // actions @IBAction func rightItemAction(_ sender: Any) { indicator.startAnimating() startBasicDemo() } func startBasicDemo() { // 最大并行数 3 operationQueue.maxConcurrentOperationCount = 3 // 添加任务下载图片 在主线程刷新UI for imageView in imageViews! { operationQueue.addOperation { if let url = URL(string: "https://placebeard.it/\(self.imgW)/\(self.imgH)") { do { let image = UIImage(data:try Data(contentsOf: url)) DispatchQueue.main.async { imageView.image = image } } catch { print(error) } } } } // 等待所有操作完成,回到主线程停止刷新器 DispatchQueue.global().async { [weak self] in self?.operationQueue.waitUntilAllOperationsAreFinished() DispatchQueue.main.async { self?.indicator.stopAnimating() } } }
解析:
operationQueue:操作队列
operationQueue.addOperation:向队列中添加任务(例子中放在for循环中,添加了多个任务)
do{} catch{}:执行任务,捕获异常
DispatchQueue.global().async:全局队列异步执行
DispatchQueue.main.async:主队列异步执行
设置队列中的优先级并执行异步任务
需求:
2.下载过程中显示loading
3.全部下载完成后停止loading
4.设置每个任务的优先级
代码:
class ConvenienceOperation: Operation { let url: URL let imageView: UIImageView init(setImageView: UIImageView,withURL: URL) { imageView = setImageView url = withURL super.init() } override func main() { do { // 当任务被取消的时候,立刻返回 if isCancelled { return } let imageData = try Data(contentsOf: url) let image = UIImage(data: imageData) DispatchQueue.main.async { [weak self] in self?.imageView.image = image } } catch { print(error) } } }
func startDependencyDemo() { operationQueue.maxConcurrentOperationCount = 4 if let url = URL(string: "https://placebeard.it/\(self.imgW)/\(self.imgH)") { let operation1 = ConvenienceOperation(setImageView: img1,withURL: url) let operation2 = ConvenienceOperation(setImageView: img2,withURL: url) let operation3 = ConvenienceOperation(setImageView: img3,withURL: url) let operation4 = ConvenienceOperation(setImageView: img4,withURL: url) // 设置依赖关系 执行顺序为 4,3,2,1 operation1.addDependency(operation2) operation2.addDependency(operation3) operation3.addDependency(operation4) // 等待所有操作完成,回到主线程停止刷新器。 DispatchQueue.global().async { [weak self] in self?.operationQueue.addOperations([operation1,operation2,operation3,operation4],waitUntilFinished: true) DispatchQueue.main.async { self?.indicator.stopAnimating() } } } }
解析:
queuePriority:任务的优先级(有高到低依次为:veryHigh、high、normal、low、veryLow),这里的优先级值得是对某一任务分配资源的优先级,由于这里设置的
maxConcurrentOperationCount(最大并行数)为2,并且任务放在异步队列里,所以看上去任务并没有按从高到低的顺序执行,如果想实现按顺序执行任务,只需将并行数设置为1,或者对任务设置依赖关系,下文会讲解到。
为队列中的任务设置依赖并异步执行任务
需求:
2.下载过程中显示loading
3.全部下载完成后停止loading
4.任务间添加依赖关系
代码:
func startDependencyDemo() { operationQueue.maxConcurrentOperationCount = 4 if let url = URL(string: "https://placebeard.it/\(self.imgW)/\(self.imgH)") { let operation1 = ConvenienceOperation(setImageView: img1,waitUntilFinished: true) DispatchQueue.main.async { self?.indicator.stopAnimating() } } } }
解析:
operation1.addDependency(operation2):operation1依赖operation2,既任务2完成后再执行任务1。