本文共 4583 字,大约阅读时间需要 15 分钟。
iOS Concurrency-依赖、取消任务
承接
依赖(Dependencies)
简单的讲就是一个任务依赖另一个任务,常用方法:
public class Operation : NSObject { public func addDependency(op: Operation) public func removeDependency(op: Operation) public var dependencies: [Operation] { get } ...}
还是紧接上一节中的例子,现有两个Operation
,一个从网络下载图片的ImageLoadOperation
,一个是处理的图片的TiltShiftOperation
。下面的例子是先
有个问题,就是如何在多个operation之间传递数据,把一个operation的输出作为一个operation的输入
1.使用另一个operation来传递数据
//加载图片let imageLoad = ImageLoadOperation()//处理图片let filter = TiltShiftOperation()imageLoad.inputName = "train_day.jpg"//传递数据的operationlet dataTransferOp = BlockOperation { filter.inputImage = imageLoad.outputImage}//添加依赖filter.addDependency(dataTransferOp)dataTransferOp.addDependency(imageLoad)//添加operation到OperationQueuelet queue = OperationQueue()duration { queue.addOperations([imageLoad, dataTransferOp, filter], waitUntilFinished: true)}
2.提供一个协议,ImageLoadOperation
实现这个协议,用来传递数据
//协议protocol FilterDataProvider { var image: UIImage? { get }}extension ImageLoadOperation: FilterDataProvider{ var image: UIImage? { return outputImage }}//修改TiltShiftOperationclass TiltShiftOperation: Operation { var inputImage: UIImage? var outputImage: UIImage? override func main() { if let dependencyImageProvider = dependencies .filter({ $0 is FilterDataProvider }) .first as? FilterDataProvider, inputImage == .none { inputImage = dependencyImageProvider.image } outputImage = tiltShift(image: inputImage) }}//加载图片let imageLoad = ImageLoadOperation()//处理图片let filter = TiltShiftOperation()filter.addDependency(imageLoad)let queue = OperationQueue()duration { queue.addOperations([imageLoad, filter], waitUntilFinished: true)}
取消任务
cancel()
方法取消operation,调用cancel()
方法并不会立即停止执行operation,调用cancel()
只是把isCancelled
属性设为true
。如果operation还没有开始运行,那么默认的start实现会阻止operation的运行,并把isFinished
设置为true。所以如果你重写start方法,也要这么做,就是要阻止已经cancel的operation。
OperationQueue
中的cancelAllOperations()
会取消队列中所有的operation
1.如有一个ArraySumOperation
,对输入数组的中的元素进行相加操作slowAdd
,所以要在for循环中处理isCancelled
的操作,如下:
public func slowAdd(_ input: (Int, Int)) -> Int { sleep(1) return input.0 + input.1}class ArraySumOperation: Operation { //输入的数组 let inputArray: [(Int, Int)] //输出的数组 var outputArray = [Int]() init(input: [(Int, Int)]) { inputArray = input super.init() } override func main() { for pair in inputArray { //如果isCancelled直接取消 if isCancelled { return } outputArray.append(slowAdd(pair)) } }}
2.还有一种情况是,假设现在不是slowAdd
,而是slowAddArray
,即直接对数组进行处理,而不是数组中元素,此时就不能在循环中判断isCancelled
,如下:
public func slowAddArray(_ input: [(Int, Int)], progress: ((Double) -> (Bool))? = nil) -> [Int] { var results = [Int]() for pair in input { results.append(slowAdd(pair)) if let progress = progress { if !progress(Double(results.count) / Double(input.count)) { return results } } } return results}
这个时候,只能在回调中处理cancel,如下:
class AnotherArraySumOperation: Operation { let inputArray: [(Int, Int)] var outputArray: [Int]? init(input: [(Int, Int)]) { inputArray = input super.init() } override func main() { outputArray = slowAddArray(inputArray, progress: { (progress) -> (Bool) in print("\(progress * 100)% of the array processed") return !self.isCancelled }) }}
3.如下,GroupAdd
管理operation queue
和多个SumOperations
,计算相加的结果,并添加结果到一个输出数组,管理队列的开始和取消,可作为参考
class GroupAdd { //操作队列 let queue = OperationQueue() //串行队列 let appendQueue = OperationQueue() var outputArray = [(Int, Int, Int)]() init(input: [(Int, Int)]) { queue.isSuspended = true queue.maxConcurrentOperationCount = 2 appendQueue.maxConcurrentOperationCount = 1 generateOperations(input) } func generateOperations(_ numberArray: [(Int, Int)]) { for pair in numberArray { //相加SumOperation let operation = SumOperation(input: pair) //计算完成的block operation.completionBlock = { guard let result = operation.output else { return } self.appendQueue.addOperation { self.outputArray.append((pair.0, pair.1, result)) } } queue.addOperation(operation) } } //开始 func start() { queue.isSuspended = false } //取消 func cancel() { queue.cancelAllOperations() } func wait() { queue.waitUntilAllOperationsAreFinished() }}
转载地址:https://windzen.blog.csdn.net/article/details/52763561 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!