Xcode 10.2 & Swift 5.0 - operation 任务

该博客围绕Xcode 10.2和Swift 5.0展开,重点提及了其中的operation任务,但具体内容未给出。推测可能涉及在这一开发环境下operation任务的使用、特性等信息技术相关内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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()

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值