Xcode 10.2 & Swift 5.0 - operation 任务

    xiaoxiao2022-07-05  178

    import Cocoa class Operation : NSObject { /// 如果operation执行的是异步任务, 需要重写此方法。 /// 可以直接调用start方法, 这将会在当前线程中执行operation任务; 也可以将operation加入到队列中, 由列队来创建线程, 执行start方法。 /// 重写此方法时, 禁止调用父类的start方法。 /// 重写此方法时, 需要手动管理各项属性, 并发送相应的KVO通知: /// - 需要反复查看isCanceled, 以确保任务被取消时执行正确操作 /// - 需要在任务结束时设置isExecuting, 当任务被取消时也要更新isExecuting /// - 需要在任务结束时设置isFinished, 当任务被取消时也要更新isFinished /// - 如果我们自定义了dependency, 还需要更新isReady /// - 需要设置isAsynchronous为true func start() /// 如果operation执行的是同步任务, 需要重写此方法。 /// 重写此方法时, 需要手动管理各项属性, 并发送相应的KVO通知: /// - 需要反复查看isCanceled, 以确保任务被取消时执行正确操作 /// - 需要在任务结束时设置isExecuting, 当任务被取消时也要更新isExecuting /// - 需要在任务结束时设置isFinished, 当任务被取消时也要更新isFinished /// - 如果我们自定义了dependency, 还需要更新isReady /// - 需要设置isAsynchronous为false func main() /// 只读属性,任务是否已被取消。 /// 这个属性会在执行cancel方法时, 自动被设置为true /// 在operation任务的代码中, 需要检查这个值, 以确定是否立刻结束任务 var isCancelled: Bool /// 仅仅标记isCancelled属性为true,并不会退出任务,和NSThread的cancel类似机制。 /// 需要在operation任务的代码中, 检查isCancelled, 以确定是否立刻结束任务 func cancel() /// 只读属性,任务是否正在执行。 /// 需要重写属性, 以加入setter方法。 /// 需要手动调用KVO方法来进行通知。 /// 需要在operation任务的代码中,手动设置这个属性。 var isExecuting: Bool /// 只读属性,任务是否结束。 /// 需要重写属性, 以加入setter方法。 /// 需要手动调用KVO方法来进行通知。 /// 当任务加入到列队中后, 队列会监听该属性的值。当isFinished设置为true后,队列将会移除这个任务。 /// 任务很可能是异步的,start方法返回也不代表任务就结束了。任务结束需要开发者手动修改该属性的值,队列就可以正常的移除任务。 var isFinished: Bool /// 该属性已经被标识即将弃用,具体含义参考请isAsynchronous。 var isConcurrent: Bool /// 只读属性,是否为异步任务,默认false。 /// 重写此属性, 将值更改为true。 var isAsynchronous: Bool /// 只读属性,任务是否准备就绪 /// 需要重写属性, 以加入setter方法。 /// 需要手动调用KVO方法来进行通知。 /// 当任务加入到列队中后, 队列会监听该属性的值。当isReady设置为true后,该任务即将开始执行。 /// 如果存在依赖的任务没有执行完成isReady为false var isReady: Bool /// 添加依赖。如果一个任务有依赖,需要等待依赖的任务执行完成才能开始执行 func addDependency(_ op: Operation) /// 删除依赖。 func removeDependency(_ op: Operation) /// 在当前操作开始执行之前完成执行的所有操作对象数组。 var dependencies: [Operation] /// 任务在队列里的优先级。 public enum QueuePriority : Int { case veryLow case low case normal case high case veryHigh } /// 任务在队列里的优先级。 /// 同一个列队中的任务, 处于isReady状态的任务, 才能执行; 存在多个isReady状态的任务时, queuePriority高的开始执行。 var queuePriority: Operation.QueuePriority /// 任务完成后的回调方法。 /// 当isFinished属性设置为true时, 会执行该回调。 var completionBlock: (() -> Void)? func waitUntilFinished() var threadPriority: Double var qualityOfService: QualityOfService var name: String? } class OperationQueue : NSObject { /// 系统规定的可以设定的最大任务并发数。 class let defaultMaxConcurrentOperationCount: Int /// 向队列中添加一个任务。 /// 任务加入到列队后, 会立刻开始执行。 func addOperation(_ op: Operation) /// 向队列中添加一组任务。 /// 任务加入到列队后, 会立刻开始执行。 /// - Parameters: /// - ops: 一组任务 /// - wait: 当wait是true时, 阻塞当前线程直到所有任务完成; 当wait是false时, 不会阻塞当前线程 func addOperations(_ ops: [Operation], waitUntilFinished wait: Bool) /// 向队列中添加一个任务,任务以block的形式传入,使用更方便。 /// 任务加入到列队后, 会立刻开始执行。 func addOperation(_ block: @escaping () -> Void) /// 获取队列中的所有任务 var operations: [Operation] /// 获取队列中的任务数量 var operationCount: Int /// 设置队列支持的最大任务并发数。 /// - count = -1, 默认值, 没有并发数限制, 所有任务并发执行。 /// - count = 1, 队列为串行队列。所有的任务, 按照加入的顺序依次执行 /// - count > 1, 队列为并发队列。所有任务并发执行,这个值不会超过defaultMaxConcurrentOperationCount。 var maxConcurrentOperationCount: Int /// 队列是否挂起。 /// - 设置为true时, 代表暂停队列 /// - 设置为false时, 代表恢复队列 /// /// 这里的暂停和取消(包括操作的取消和队列的取消)并不代表可以将当前的操作立即取消,而是当当前的操作执行完毕之后不再执行新的操作。 /// 暂停和取消的区别就在于:暂停操作之后还可以恢复操作,继续向下执行;而取消操作之后,所有的操作就清空了,无法再接着执行剩下的操作。 var isSuspended: Bool /// 队列的名称 var name: String? var qualityOfService: QualityOfService unowned(unsafe) var underlyingQueue: DispatchQueue? /// 取消队列中的所有任务 /// 即所有任务都执行cancel方法,所有任务的isCancelled属性都置为true func cancelAllOperations() /// 阻塞当前线程直到所有任务完成 func waitUntilAllOperationsAreFinished() /// 类属性,获取当前线程中正在执行的队列 class var current: OperationQueue? /// 类属性,获取主队列。 /// 任务添加到主队列就会使用主线程执行,主队列的任务并发数为1,即串行队列。但是不包括使用addExecutionBlock:添加的额外任务,额外任务可能在其他线程执行。 class var main: OperationQueue } /// 场景1: 从指定URL中下载数据 class Crawler : Operation, URLSessionDownloadDelegate { private var url : URL private var session : URLSession! private var task : URLSessionDownloadTask! private var _isFinished : Bool = false /// 需要重写这个属性, 才有setter方法 /// 这只是个计算属性, 为了getter方法, 需要另外一个值作为存储属性 /// 需要加入方法, 以触发KVO, 本例中发现不需要指定dynamic关键字 /// TODO: 目前不清楚isExecuting能触发什么操作 override var isFinished: Bool { set { willChangeValue(forKey: "isFinished") _isFinished = newValue didChangeValue(forKey: "isFinished") } get { return _isFinished } } init(_ url: String) { self.url = URL(string: url)! super.init() self.session = URLSession(configuration: .default, delegate: self, delegateQueue: nil) } override func start() { task = session.downloadTask(with: url) task.resume() } override var isAsynchronous: Bool { return true } override func cancel() { super.cancel() task.cancel() } /// 本例中调用了cancel方法, 代码也一定是在这个委托方法中结束, 并不会在后面两个方法中结束, 这说明operation.cancel方法并不能强制结束正在执行的任务 func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { if let error = error as NSError? { print("\(name!) didCompleteWithError: \(error.localizedDescription)") } else { print("didComplete") } isFinished = true } func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { if isCancelled { print("\(name!) didFinishDownloadingTo = \(location.absoluteString), cancelled") } else { print("\(name!) didFinishDownloadingTo = \(location.absoluteString)") } } func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { if isCancelled { print("\(name!) totalBytesWritten = \(totalBytesExpectedToWrite) | \(totalBytesWritten), didWriteData = \(bytesWritten), cancelled") } else { print("\(name!) totalBytesWritten = \(totalBytesExpectedToWrite) | \(totalBytesWritten), didWriteData = \(bytesWritten)") } } } /// KVO 需要在对象中执行 class Example : NSObject { func test() { let op1 = Crawler("http://m6.pc6.com/xuh6/eZip173.dmg") op1.name = "op1" // Crawler中指定了 isFinished = true, 才会执行这个闭包 op1.completionBlock = { print("op1 is completion") } op1.addObserver(self, forKeyPath: "isFinished", options: .new, context: nil) let op2 = Crawler("http://m6.pc6.com/xuh6/winzip654149.dmg") op2.name = "op2" op2.completionBlock = { print("op2 is completion") } op2.addObserver(self, forKeyPath: "isFinished", options: .new, context: nil) let queue = OperationQueue() // 指定为1时, op1和op2按照先后加入的顺序, 依次执行 //queue.maxConcurrentOperationCount = 1 queue.addOperation(op1) queue.addOperation(op2) DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + 3) { queue.cancelAllOperations() } } override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { guard let op = object as? Crawler else { print("object is not a `Crawler`") super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) return } if keyPath != "isFinished" { print("keyPath is `\(keyPath!)`") super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) return } let newValue = change![.newKey] as! Bool print("\(op.name!).isFinished change to \(newValue)") } } let example = Example() example.test()

     

    最新回复(0)