iOS多线程NSOperation篇

The NSOperation  class is an abstract class you use to encapsulate the code and data associated with a single task. Because it is abstract, you do not use this class directly but instead subclass or use one of the system-defined subclasses (NSInvocation​Operation or NSBlock​Operation) to perform the actual task. Despite being abstract, the base implementation of NSOperation does include significant logic to coordinate the safe execution of your task. The presence of this built-in logic allows you to focus on the actual implementation of your task, rather than on the glue code needed to ensure it works correctly >with other system objects.   -- 引自官方文档NSOperation Class Reference

官方文档很清晰的给我们解释了NSOperation是个什么玩意,所以这里也就不赘述NSOperation的基础定义了,接下来会对NSOperation.h为我们提供的一些属性和API做一些简单的释义,顺便看一下怎么使用。

NSOperation.h

NSOperation.h里边共包含四个类是属性与API,先来看一下NSOperation的:

1. NSOperation

NSOperation的属性与方法:

@interface NSOperation : NSObject {
@private
    id _private;
    int32_t _private1;
#if __LP64__
    int32_t _private1b;
#endif
}

- (void)start;
- (void)main;

@property (readonly, getter=isCancelled) BOOL cancelled;
- (void)cancel;

@property (readonly, getter=isExecuting) BOOL executing;
@property (readonly, getter=isFinished) BOOL finished;
@property (readonly, getter=isConcurrent) BOOL concurrent; // To be deprecated; use and override 'asynchronous' below
@property (readonly, getter=isAsynchronous) BOOL asynchronous NS_AVAILABLE(10_8, 7_0);
@property (readonly, getter=isReady) BOOL ready;

- (void)addDependency:(NSOperation *)op;
- (void)removeDependency:(NSOperation *)op;

@property (readonly, copy) NSArray<NSOperation *> *dependencies;

typedef NS_ENUM(NSInteger, NSOperationQueuePriority) {
	NSOperationQueuePriorityVeryLow = -8L,
	NSOperationQueuePriorityLow = -4L,
	NSOperationQueuePriorityNormal = 0,
	NSOperationQueuePriorityHigh = 4,
	NSOperationQueuePriorityVeryHigh = 8
};

@property NSOperationQueuePriority queuePriority;

@property (nullable, copy) void (^completionBlock)(void) NS_AVAILABLE(10_6, 4_0);

- (void)waitUntilFinished NS_AVAILABLE(10_6, 4_0);

@property double threadPriority NS_DEPRECATED(10_6, 10_10, 4_0, 8_0);

@property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0);

@property (nullable, copy) NSString *name NS_AVAILABLE(10_10, 8_0);

@end
复制代码

以上,就是NSOperation.h对我们提供所有属性和方法。接下来就慢慢的看看它们的使用吧。

  • -(void)start;

    从名字就可以看出来它的作用,开始执行某个NSOperation。除此之外还有另外两个需要我们知道的知识:

    1. 放入队列中的NSOperation对象不需要调用start方法,NSOPerationQueue会在『合适』的时机去自动调用。当然,如果你不需要NSOperationQueue去调用也可以手动调用,这块知识后边会讲到
    2. start方法的重写问题,这个问题也留到后边继承模块讲
    3. 手动的调用start方法后,这个操作会在当前调用的线程进行同步执行,所以在主线程里面自己一定要小心的调用,不然就会把主线程给卡死。
  • -(void) main;

    这个方法在纯粹的NSOperation的使用中基本用不到,特殊情况就不考虑了,在后边继承模块会讲到关于main方法重写问题需要注意的事情。

  • -(void) cancel;

    关于cancel方法官方文档是这样解释的Advises the operation object that it should stop executing its task.也就是说调用这个方法之后线程并不会立即停止,只是会做一个标志,系统会在之后找合适的时机停止这个线程。

  • @property (readonly, getter=isCancelled) BOOL cancelled;

    这个属性也是证明了cancel方法调用之后并不会立即停止operation操作,cancelled这个属性就是查询操作过的operation对象是否添加取消标志。

  • @property (readonly, getter=isExecuting) BOOL executing;

  • @property (readonly, getter=isFinished) BOOL finished;

  • @property (readonly, getter=isConcurrent) BOOL concurrent; // To bedeprecated; use and override 'asynchronous' below

  • @property (readonly, getter=isAsynchronous) BOOL asynchronous NS_AVAILABLE(10_8, 7_0);

  • @property (readonly, getter=isReady) BOOL ready;

    接下来这几个属性都是用来表示operation操作的状态的,这边会涉及到一个知识:operation的状态,从operation创建开始到结束会有多个状态,上边的属性就是为我们提供查询operation操作的状态进入到哪一步了,可以针对状态作对响应的操作,状态列表会在NSOperation模块最后做给出。

  • (void)addDependency:(NSOperation )op;

  • (void)removeDependency:(NSOperation )op;

    这两个方法是设置依赖的,关于依赖的释义会在本模块后边给出。

  • @property (readonly, copy) NSArray<NSOperation *>*dependencies;

    官方文档是这样解释这个属性的An array of the operation objects that must finish executing before the current object can begin executing.也就是说,这个属性是查询某个operation执行之前需要执行的所有操作。

  • @property NSOperationQueuePriority queuePriority;

    设置operation操作的优先级,在它之前有这样一个属性:thread​Priority ,不过在iOS8.0之后已经不使用了,下边是operation的优先级枚举:

    typedef NS_ENUM(NSInteger, NSOperationQueuePriority) {
    NSOperationQueuePriorityVeryLow = -8L,
    NSOperationQueuePriorityLow = -4L,
    NSOperationQueuePriorityNormal = 0,
    NSOperationQueuePriorityHigh = 4,
    NSOperationQueuePriorityVeryHigh = 8
    };
    复制代码
  • @property (nullable, copy) void (^completionBlock)(void) NS_AVAILABLE(10_6, 4_0);

    The block to execute after the operation’s main task is completed.,简单来说就是当所有的operation操作结束以后想做什么操作可以在这个block里边写。

  • - (void)waitUntilFinished NS_AVAILABLE(10_6, 4_0);

    停止当前任务,知道操作对象将其他任务全部执行完毕之后再执行。

  • @property double threadPriority NS_DEPRECATED(10_6, 10_10, 4_0, 8_0);

    同queuePriority。

  • @property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0);

    这是iOS8.0以后苹果提供的新功能,通过这个属性告诉系统我们在进行什么样的工作,然后系统会通过合理的资源控制来最高效的执行任务代码,其中主要涉及到CPU调度的优先级、IO优先级、任务运行在哪个线程以及运行的顺序等等,我们通过一个抽象的Quality of Service参数来表明任务的意图以及类别。

    NSQualityOfServiceUserInteractive
    与用户交互的任务,这些任务通常跟UI级别的刷新相关,比如动画,这些任务需要在一瞬间完成
    NSQualityOfServiceUserInitiated
    由用户发起的并且需要立即得到结果的任务,比如滑动scroll view时去加载数据用于后续cell的显示,这些任务通常跟后续的用户交互相关,在几秒或者更短的时间内完成
    NSQualityOfServiceUtility
    一些可能需要花点时间的任务,这些任务不需要马上返回结果,比如下载的任务,这些任务可能花费几秒或者几分钟的时间
    NSQualityOfServiceBackground
    这些任务对用户不可见,比如后台进行备份的操作,这些任务可能需要较长的时间,几分钟甚至几个小时
    NSQualityOfServiceDefault
    优先级介于user-initiated 和 utility,当没有     QoS信息时默认使用,开发者不应该使用这个值来设置自己的任务
    复制代码
  • @property (nullable, copy) NSString *name NS_AVAILABLE(10_10, 8_0);

    operation对象的名称

以上,就是NSOperation.h为我们提供的所有关于NSOperation的属性与方法。

状态
  • is​Cancelled - read-only
  • is​Asynchronous - read-only
  • is​Executing - read-only
  • is​Finished - read-only
  • is​Ready - read-only
  • dependencies - read-only
  • queue​Priority - readable and writable
  • completion​Block - readable and writable

很多时候我们都需要根据当前操作的状态做后续的事情,比如在完成下载任务后更新主线程。以上几种状态都是基于keypath的KVO通知决定,所以在你手动改变某个操作的状态时,请别忘了手动发送通知。这里面每个属性都是相互独立的,同时只可能有一个状态是YES。如果你手动管理过某个操作的状态,切记在操作完成后将finished这个状态设置为YES,因为在NSOperationQueue所管理的队列中,只有isFinished为YES时才将其移除队列,如果不修改这个值,很可能会产生内存或者死锁问题。

依赖

关于依赖的说明最好看一下官方文档,下边这段话是官方文档里边对依赖的介绍:

Dependencies are a convenient way to execute operations in a specific order. You can add and remove dependencies for an operation using the add​Dependency:​ and remove​Dependency:​ methods. By default, an operation object that has dependencies is not considered ready until all of its dependent operation objects have finished executing. Once the last dependent operation finishes, however, the operation object becomes ready and able to execute.

简单来说就是确定任务之间的关系,设置任务执行的顺序。添加和删除依赖的方法上边已经说过了。需要注意的是依赖不能互相设置,比如A依赖B,B又依赖于A,这样就会导致死锁!还有一点必须要注意的是,在每个操作完成时,请将isFinished设置为YES,不然后续的操作是不会开始执行的。

2. NSBlockOperation

首先要说NSBlockOperation是继承自NSOperation的,在其上做了一些封装。NSBlockOperation的官方网址在这:NSBlockOperation。 需要知道的关于NSBlockOperation的知识:

  1. 默认的执行方式是并行的,并且有最大并发数量,但是机型不同最大并发数量也不相同,所以我们不需要关系最大并发数量的问题。
  2. 添加到block里边的事件并不会完全开辟子线程执行,而是优先放到主线程执行。
  3. 因为是集成于NSOperation,所以NSOperation的一些特性都具有,比如:
    • 支持一个可选的 completion block ,这个 block 将会在 operation 的主任务执行完成时被调用;
    • 支持通过 KVO 来观察 operation 执行状态的变化;
    • 支持设置执行的优先级,从而影响 operation 之间的相对执行顺序;
    • 支持取消操作,可以允许我们停止正在执行的 operation 。

NSBlockOperation在NSOperation的基础上为我们新提供了一个类方法,一个实例方法和一个属性:

  • + (instancetype)blockOperationWithBlock:(void (^)(void))block;

    伴随着一个block创建一个operation操作

  • - (void)addExecutionBlock:(void (^)(void))block;

    添加一个block,block里边就是需要执行的任务代码

  • *@property (readonly, copy) NSArray<void (^)(void)> executionBlocks;

    存放所有添加到当前operation的操作

下边是使用方式:

NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"第一个线程");
}];
[blockOperation addExecutionBlock:^{
    NSLog(@"第二个线程");
}];
[blockOperation addExecutionBlock:^{
    NSLog(@"第三个线程");
}];
[blockOperation addExecutionBlock:^{
    NSLog(@"第四个线程");
}];

NSLog(@"%@",blockOperation.executionBlocks);

[blockOperation start];
复制代码
3. NSInvocationOperation

NSInvocationOperation也是集成自NSOperation的,如果是单独使用的话并没有什么太大的作用,需要跟着后边NSOperationQueue配合使用才会产生效果。这里是官方文档地址:NSInvocationOperation

下边是属性和API:

  • - (nullable instancetype)initWithTarget:(id)target selector:(SEL)sel object:(nullable id)arg;

    初始化一个NSInvocationOperation实例,后边和button添加点击事件比较像,传入一个目标,一个事件,最后一个是参数。

  • - (instancetype)initWithInvocation:(NSInvocation *)inv NS_DESIGNATED_INITIALIZER;

    根据传入NSInvocation创建一个NSInvocationOperation实例。

  • @property (readonly, retain) NSInvocation *invocation;

    打印NSInvocationOperation的invocation属性,只读。

  • @property (nullable, readonly, retain) id result;

    这个属性是标志着传入事件的返回结果

需要注意的是:如果创建完毕后直接调用start方法,那么这个操作默认会在主线程中执行。

4. NSOperationQueue

接下来就是NSOperationQueue了,这个类在iOS的日常开发中还是比较常见的。首先还是NSOperationQueue的官方地址:NSOperationQueue。 接下来就一边看着官方文档一边写释义吧

The NSOperation​Queue  class regulates the execution of a set of NSOperation  objects. After being added to a queue, an operation remains in that queue until it is explicitly canceled or finishes executing its task. Operations within the queue (but not yet executing) are themselves organized according to priority levels and inter-operation object dependencies and are executed accordingly. An application may create multiple operation queues and submit operations to any of them.

这是官方文档里对NSOperationQueue的介绍。将创建好的Operation对象添加到NSOperationQueue操作队列里,添加之后操作将保留在该队列中,直到手动取消或此任务被执行完毕才会被移除释放。队列内的操作(尚未执行)根据优先级和互操作对象依赖性进行组织,并相应执行。应用程序可以创建多个操作队列并向其中任何一个提交操作。

然后来看一下NSOperation​Queue属性与方法:

@interface NSOperationQueue : NSObject {
@private
    id _private;
    void *_reserved;
}

- (void)addOperation:(NSOperation *)op;
- (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait NS_AVAILABLE(10_6, 4_0);

- (void)addOperationWithBlock:(void (^)(void))block NS_AVAILABLE(10_6, 4_0);

@property (readonly, copy) NSArray<__kindof NSOperation *> *operations;
@property (readonly) NSUInteger operationCount NS_AVAILABLE(10_6, 4_0);

@property NSInteger maxConcurrentOperationCount;

@property (getter=isSuspended) BOOL suspended;

@property (nullable, copy) NSString *name NS_AVAILABLE(10_6, 4_0);

@property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0);

@property (nullable, assign /* actually retain */) dispatch_queue_t underlyingQueue NS_AVAILABLE(10_10, 8_0);

- (void)cancelAllOperations;

- (void)waitUntilAllOperationsAreFinished;

#if FOUNDATION_SWIFT_SDK_EPOCH_AT_LEAST(8)
@property (class, readonly, strong, nullable) NSOperationQueue *currentQueue NS_AVAILABLE(10_6, 4_0);
@property (class, readonly, strong) NSOperationQueue *mainQueue NS_AVAILABLE(10_6, 4_0);
#endif

@end
复制代码

上边还是Operation.h文件里边为我们提供的NSOperationQueue的属性和方法,然后接下来就是详细的解释:

  • - (void)addOperation:(NSOperation *)op;

    给队列里边添加一个Operation操作。

  • - (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait NS_AVAILABLE(10_6, 4_0);

    给队列里边添加一组Operation操作,并且决定是否阻塞当前线程,知道所有Operation操作执行完毕。

  • - (void)addOperationWithBlock:(void (^)(void))block NS_AVAILABLE(10_6, 4_0);

    利用block创建一个新的Operation操作,并且添加到队列里边。

  • @property (readonly, copy) NSArray<__kindof NSOperation *> *operations;

    用来保存队列里边所有的Operation操作。

  • @property (readonly) NSUInteger operationCount NS_AVAILABLE(10_6, 4_0);

    任务数量

  • @property NSInteger maxConcurrentOperationCount;

    最大并发数量,默认为-1,就是不限制并发数量。设置为 1 的话就相当于FIFO。如需自定义,作为移动端开发,一般以 3 以内为宜,因为虽然任务是在子线程进行处理的,但是 CPU 处理这些过多的子线程可能会影响 UI,让 UI 变卡。

  • @property (getter=isSuspended) BOOL suspended;

    队列是否正常执行,如果为NO的话就会阻塞队列的执行。可以用来做暂停和继续。

  • @property (nullable, copy) NSString *name NS_AVAILABLE(10_6, 4_0);

    队列名称

  • @property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0);

    和Operation的qualityOfService一样,这里就不多做解释了

  • @property (nullable, assign * actually retain *) dispatch_queue_t underlyingQueue NS_AVAILABLE(10_10, 8_0);

    iOS8.0以后出来的属性,并没有试出来是干嘛的,也没感觉有什么作用,官方文档是这样说明的

    The dispatch queue used to execute operations. The default value of this property is nil. You can set the value of this property to an existing dispatch queue to have enqueued operations interspersed with blocks submitted to that dispatch queue. The value of this property should only be set if there are no operations in the queue; setting the value of this property when operation​Count is not equal to 0 raises an NSInvalid​Argument​Exception. The value of this property must not be the value returned by dispatch_get_main_queue. The quality-of-service level set for the underlying dispatch queue overrides any value set for the operation queue's quality​Of​Service property.

以后找到用到的地方再回来补吧

  • - (void)cancelAllOperations;

    取消队列里边所有的Operation操作

  • - (void)waitUntilAllOperationsAreFinished;

    阻塞当前任务的执行,直到队列里边其他任务全部执行完毕之后再继续执行。

  • *@property (class, readonly, strong, nullable) NSOperationQueue currentQueue NS_AVAILABLE(10_6, 4_0);

    返回当前操作所在的操作队列

  • @property (class, readonly, strong) NSOperationQueue *mainQueue NS_AVAILABLE(10_6, 4_0);

    返回与主线程关联的操作队列

以上,就是NSOperationQueue的属性与方法。

附上一段基础方法与属性的使用:

NSOperationQueue*queue = [[NSOperationQueue alloc]init];
NSOperation*op1 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"执行任务1");
    sleep(2);
}];
NSOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"执行任务4");
    sleep(2);
}];
NSOperation*op2 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"执行任务2,并且取消任务4");
    [op4 cancel];
    sleep(2);
}];

NSOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"执行任务3");
    sleep(2);
    //回主线程渲染图片
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        NSLog(@"回主线程执行任务");
        sleep(2);
    }];
}];

NSOperation *op5 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"执行任务5");
    sleep(2);
}];

NSOperation *op6 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"执行任务6");
    sleep(2);
}];

NSOperation *op7 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"执行任务7");
    sleep(2);
}];

//监听任务是否执行完毕
op1.completionBlock = ^(){
    NSLog(@"任务1执行完毕");
    sleep(2);
};
op2.completionBlock = ^(){
    NSLog(@"任务2执行完毕");
    sleep(2);
};
op3.completionBlock = ^(){
    NSLog(@"任务3执行完毕");
    sleep(2);
};
op4.completionBlock = ^(){
    NSLog(@"任务4执行完毕");
    sleep(2);
};
op5.completionBlock = ^(){
    NSLog(@"任务5执行完毕");
    sleep(2);
};
op6.completionBlock = ^(){
    NSLog(@"任务6执行完毕");
    sleep(2);
};
op7.completionBlock = ^(){
    NSLog(@"任务7执行完毕");
    sleep(2);
};
//添加依赖
[op2 addDependency:op1];
[op3 addDependency:op2];
[op4 addDependency:op3];
[op5 addDependency:op3];
[op6 addDependency:op5];
[op7 addDependency:op6];
//添加任务
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
[queue addOperation:op4];
[queue addOperation:op5];
[queue addOperation:op6];
[queue addOperation:op7];

[queue waitUntilAllOperationsAreFinished];
NSLog(@"所有任务都执行完毕了");
复制代码

执行一下这段代码会发现几个问题:

  1. op5不同于其他操作,他是直接依赖于op3的。
  2. op4并没有打印执行代码,但是执行完毕代码被打印了。
  3. 并不是任务执行完毕之后才会执行下一个任务,就算是有依赖关系也是这样
  4. 任务3里边的返回主线程任务是在所有任务执行完毕之后才执行的

上述问题就不做解释了,大家可以自己考虑一下为什么。

OperationQueue和DispatchQueue的不同:

  • 不遵循 FIFO(先进先出):在 Operation Queues 中,你可以设置 operation(操作)的执行优先级,并且可以在 operation 之间添加依赖,这意味着你可以定义某些 operation,使得它们可以在另外一些 operation 执行完毕之后再被执行。这就是为什么它们不遵循先进先出的顺序。
  • 默认情况下 Operation Queues 是并发执行:虽然你不能将其改成串行队列,但还是有一种方法,通过在 operation 之间添加相依性来让 Operation Queues 中的任务按序执行。
  • Operation Queues 是 NSOperationQueue 类的实例,任务被封装在 NSOperation 的实例中。

自定义NSOperation

当上述内容都不能满足你的需要时,我们可以尝试自己定义一个NSOperation。 如果你的应用只需要非并发的NSOperation,自定义的时候必须要重写的方法只有一个:

  • main方法
 - (void)main
{
    NSLog(@"main begin");
    //捕获异常
    @try {
        //在这里我们要创建自己的释放池,因为这里我们拿不到主线程的释放池
        @autoreleasepool {
            // 提供一个变量标识,来表示需要执行的操作是否完成了,当然,没开始执行之前,为NO
            BOOL taskIsFinished = NO;
            // while 保证:只有当没有执行完成和没有被取消,才执行自定义的相应操作
            while (taskIsFinished == NO && [self isCancelled] == NO){
                // 自定义的操作
                sleep(10);  // 睡眠模拟耗时操作
                NSLog(@"currentThread = %@", [NSThread currentThread]);
                NSLog(@"mainThread    = %@", [NSThread mainThread]);
                // 这里相应的操作都已经完成,后面就是要通知KVO我们的操作完成了。
                taskIsFinished = YES;
            }
        }
    }
    @catch (NSException *exception) {
        NSLog(@"Exception %@", exception);
    }
    NSLog(@"main end");
}
复制代码

如果我们的应用需要并发的NSOperation,自定义的时候需要做的事情就比较多了,首先看一下这个表格:

| 方法 | 描述 | | :: |::| | start | (必选)所有的并发Operation必需重写这个方法并且要实现这个方法的内容来代替原来的操和。手动执行一个操作,你可以调用start方法。因此,这个方法的实现是这个操作的始点,也是其他线程或者运行这你这个任务的起点。注意一下,在这里永远不要调用[super start]。 | | main | (可选)这个方法就是你的实现的操作(懒得翻译了,哈哈) | | isExecuting 和 isFinish | (必选)并发队列负责维持当前操作的环境和告诉外部调用者当前的运行状态。因此,一个并发队列必需维持保持一些状态信息以至于知道什么时候执行任务,什么时候完成任务。它必须通过这些方法告诉外部当前的状态。这种而且这些方法必须是线程安全,当状态发生改变的时候,你必须使用KVO通知监听这些状态的对象 | | isConcurrent | (必选)定义一个并发操作,重写这个方法并且返回YES |

所以说,如果我们想要自定义一个并发的NSOperation,我们可能需要重写的方法如下:

  • start: 所有并行的 Operations 都必须重写这个方法,然后在你想要执行的线程中手动调用这个方法。注意:任何时候都不能调用父类的start方法。
  • main: 在start方法中调用,但是注意要定义独立的自动释放池与别的线程区分开。
  • isExecuting: 是否执行中,需要实现KVO通知机制。
  • isFinished: 是否已完成,需要实现KVO通知机制。
  • isConcurrent: 该方法现在已经由isAsynchronous方法代替,并且NSOperationQueue 也已经忽略这个方法的值。
  • isAsynchronous: 该方法默认返回 NO ,表示非并发执行。并发执行需要自定义并且返回 YES。后面会根据这个返回值来决定是否并发。

与非并发操作不同的是,需要另外自定义一个方法来执行操作而不是直接调用-(void)start;方法

下边是一份示例代码

- (id)init {  
    if(self = [super init])  
    {  
        executing = NO;  
        finished = NO;  
    }  
    return self;  
}  
- (BOOL)isConcurrent {  
    return YES;  
}  
- (BOOL)isExecuting {  
    return executing;  
}  
- (BOOL)isFinished {  
    return finished;  
}  
  
- (void)start {  
      
    //第一步就要检测是否被取消了,如果取消了,要实现相应的KVO  
    if ([self isCancelled]) {  
        [self willChangeValueForKey:@"isFinished"];  
        finished = YES;  
        [self didChangeValueForKey:@"isFinished"];  
        return;  
    }  
      
    //如果没被取消,开始执行任务  
    [self willChangeValueForKey:@"isExecuting"];  
      
    [NSThread detachNewThreadSelector:@selector(main) toTarget:self withObject:nil];  
    executing = YES;  
    [self didChangeValueForKey:@"isExecuting"];  
}  
  
- (void)main {  
// 异常捕获
    @try {  
      // 防止内存不释放
        @autoreleasepool {  
            //在这里定义自己的并发任务  
            NSLog(@"自定义并发操作NSOperation");  
            NSThread *thread = [NSThread currentThread];  
            NSLog(@"%@",thread);  
              
            //任务执行完成后要实现相应的KVO  
            [self willChangeValueForKey:@"isFinished"];  
            [self willChangeValueForKey:@"isExecuting"];  
              
            executing = NO;  
            finished = YES;  
              
            [self didChangeValueForKey:@"isExecuting"];  
            [self didChangeValueForKey:@"isFinished"];  
        }  
    }  
    @catch (NSException *exception) {    
    }  
}  
复制代码

OK,以上就是NSOperation的初步调研结果,后续有时间会针对它的实现原理续写一篇文章。



有志者、事竟成,破釜沉舟,百二秦关终属楚;

苦心人、天不负,卧薪尝胆,三千越甲可吞吴.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值