Operation源码分析

本文分析了NSOperation在Swift中的实现原理,包括同步和异步执行、OperationQueue的初始化、添加任务、调度及执行任务的过程。重点探讨了Operation的状态管理、start方法以及KVO在任务监控中的应用。阅读源代码有助于深入理解Operation Queue的工作机制。
摘要由CSDN通过智能技术生成

前言

NSOperation是Foundation中用于多线程并发任务的抽象类,它可以放到NSOperationQueue任务队列中去执行。它底层还是基于GCD来实现的,相比GCD它支持取消操作和依赖管理。

Apple用swift重写了Foundation库并且开源,可以通过阅读NSOperation的swift源代码来了解其实现原理。

https://github.com/apple/swift-corelibs-foundation/blob/main/Sources/Foundation/Operation.swift 点击跳转

在分析源代码之前也请阅读一下苹果的《Concurrency Programming Guide》的Operation Queues一章,要了解如何使用Operation。

同步和异步

NSOperation是抽象类,使用它需要子类继承它,并覆写一些成员方法。

它有两种模式,一种是同步执行,一种是异步执行。

同步执行,需要覆写main方法即可。

@interface MyOperation : NSOperation
@end

@implementation MyOperation
- (void)main {
  // 要实现的业务逻辑写这里即可
}
@end

当main方法返回的时候,任务也就结束了。

异步执行,需要覆写start方法,同时实现asynchronous、concurrent、executing和finished属性。

@interface MyOperation : NSOperation {
  BOOL _executing;
  BOOL _finished;
}

@property (nonatomic, assign, getter = isExecuting) BOOL executing;
@property (nonatomic, assign, getter = isFinished) BOOL finished;

@end

@implementation MyOperation

@synthesize executing = _executing;
@synthesize finished = _finished;

- (void)start {
  // 要实现的业务逻辑写这里即可
}

- (BOOL)isAsynchronous {
    return YES;
}

- (BOOL)isConcurrent {
    return YES;
}

- (void)setFinished:(BOOL)finished {
    [self willChangeValueForKey:@"isFinished"];
    _finished = finished;
    [self didChangeValueForKey:@"isFinished"];
}

- (void)setExecuting:(BOOL)executing {
    [self willChangeValueForKey:@"isExecuting"];
    _executing = executing;
    [self didChangeValueForKey:@"isExecuting"];
}
@end

当start方法返回的时候,任务可以继续执行,直到任务真正执行完毕,我们执行self.finished=YES; self.executing=YES;通过KVO的方式通知NSOperation任务已经执行完毕,可以从NSOperationQueue中移除此任务了。

OperationQueue

OperationQueue是任务的执行队列

初始化

OperationQueue有两个初始化方法:

一个是public方法给大家创建任务队列使用的

open class OperationQueue : NSObject, ProgressReporting {

    // 任务队列名字
    var __name: String?

    // 对外的初始化方法
    public override init() {
        super.init()
        __name = "NSOperationQueue \(Unmanaged<OperationQueue>.passUnretained(self).toOpaque())"
    }
}

另一个是internal方法,专门用来初始化mainQueue的

extension OperationQueue {
    public static let defaultMaxConcurrentOperationCount: Int = -1
}

open class OperationQueue : NSObject, ProgressReporting {

    // 是否是主线程队列
    var __mainQ: Bool = false

    // 并发数上限
    var __maxNumOps: Int = OperationQueue.defaultMaxConcurrentOperationCount

    // 实际并发数上限
    var __actualMaxNumOps: Int32 = .max

    // 任务队列名字
    var __name: String?

    // QOS,任务队列的优先级
    var __propertyQoS: QualityOfService?

    // asMainQueue是一个空元组,只是为了重载init方法,方便内部使用
    internal init(asMainQueue: ()) {
        super.init()
        __mainQ = true
        __maxNumOps = 1
        __actualMaxNumOps = 1
        __name = "NSOperationQueue Main Queue"
#if canImport(Darwin)
        __propertyQoS = QualityOfService(qos_class_main())
#else
        __propertyQoS = QualityOfService.userInteractive
#endif
    }

    // 返回主线程任务队列
    open class var main: OperationQueue {
        get {
            struct Once {
                // 使用static保证了变量只初始化一次
                static let mainQ = OperationQueue(asMainQueue: ())
            }
            return Once.mainQ
        }
    }
}

添加任务

添加一个Operation到任务队列中,对外提供了两个方法,可以添加单个任务或者批量任务。

open class OperationQueue : NSObject, ProgressReporting {
    
    // 添加单个任务
    open func addOperation(_ op: Operation) {
        _addOperations([op], barrier: false)
    }
    
    // 添加多个任务,同时支持设置是否同步等待
    open func addOperations(_ ops: [Operation], waitUntilFinished wait: Bool) {
        _addOperations(ops, barrier: false)
        if wait {
            for op in ops {
                op.waitUntilFinished()
            }
        }
    }
}

对内提供了一个下划线开头的批量添加任务方法,所有的添加任务,都最终会走到此方法中

open class OperationQueue : NSObject, ProgressReporting {

    internal func _addOperations(_ ops: [Operation], barrier: Bool = false) {
        // 判空保护
        if ops.isEmpty { return }
        
        // 失败数
        var failures = 0
        
        // 成功数
        var successes = 0

        // 第一个新任务
        var firstNewOp: Unmanaged<Operation>?

        // 上一个新任务
        var lastNewOp: Unmanaged<Operation>?

        // 循环传入的任务数组
        for op in ops {

            // 对op的状态进行CAS修改,从initialized修改成enqueuing
            if op._compareAndSwapState(.initialized, .enqueuing) {

                // 如果修改成功,成功数累加1
                successes += 1

                // 判断之前的修改是否都成功
                if 0 == failures {

                    // 走到这里,说明所有的任务的状态都正确修改成e
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值