NSOperation

NSOperation参考链接

NSOperation

继承自NSObject

NSInvocationOperation

直接在当前线程执行任务,不支持并发,因为初始化方法只支持执行一个任务,并且没有添加任务的方法。

- initWithTarget:selector:object:
- initWithInvocation:

NSBlockOperation

  1. 当任务加入队列时,会开辟新线程
  2. 当任务数等于1时,不会开辟新线程,在当前线程同步执行
  3. 当任务数大于1时会开辟新线程
  4. NSBlockOperation添加操作数大于1时,除第一个任务外,其任务就是异步执行

自定义子类

  1. 同步
    直接冲洗main方法就可以
    默认情况下,该operation在当前调用start的线程中执行.其实如果我们创建多个自定义的ZCNoCurrentOperation,并放入NSOperationQueue中,这些任务也是并发执行的,只不过因为我们没有处理并发情况下,线程执行完,KVO等操作,因此不建议在只实现main函数的情况下将其加入NSOperationQueue,只实现main一般只适合自定义非并发的。

  2. 异步
    start、asynchronous、executing、finished。并且需要自己创建自动释放池,因为异步操作无法访问主线程的自动释放池。
    原因:main方法的话,如果main方法执行完毕,那么整个operation就会从队列中被移除。如果你是一个自定义的operation并且它是某些类的代理,这些类恰好有异步方法,这是就会找不到代理导致程序出错了。然而start方法就算执行完毕,它的finish属性也不会变,因此你可以控制这个operation的生命周期了。然后在任务完成之后手动cancel掉这个operation即可。

注意点:If you provide custom implementations for any of the preceding properties, your implementations must maintain KVC and KVO compliance. If you define additional properties for your NSOperation objects, it is recommended that you make those properties KVC and KVO compliant as well.

NSOperationQueue

只要是创建了队列,在队列中的操作,就会在子线程中执行,并且默认并发操作。添加到子队列NSOperationQueue实例中的操作,都是异步执行
添加操作到NSOperationQueue中,自动执行操作,自动开启线程
从多个线程中使用一个NSOperationQueue对象是安全的,无需创建额外的锁来同步对该对象的访问。

suspended、cancel、cancelAllOperation

三者的共同点:如果任务已经在线程中执行,则不受此影响。
suspended:当NSOperationQueue对象属性suspended设置为YES,是队列停止了对任务调度。
一个操作执行还未完成时,我们可能需要让该任务暂停、可能之后在进行某些操作后又希望继续执行。影响的是加入队列,但未被调度到线程中正在执行的任务。如果任务已经在线程中执行,则不受此影响。
cancel cancelAllOperation:一旦调用了这2个方法,操作对象将无法恢复
只有队列标记为已经结束时才会从队列中移除,如果任务已经在线程中执行,则不受此影响。
对于队列中的操作,只有操作标记为已结束才能被队列移除。在队列中未被调度的操作,会调用start方法执行操作,以便操作对象处理取消事件。然后标记这些操作对象为已结束。对于正在线程中执行其任务的操作对象,正在执行的任务会继续执行,该操作对象会被标记经结束。

suspended、cancel、cancelAllOperation 注意:只会停止调度队列中操作对象,正在执行任务的依然会执行,且取消不可恢复。

依赖

操作添加到队列添加的顺序并不能决定执行顺序,执行的顺序取决于多种因素比如依赖、优先级等。

线程安全

NSOperation实例在多线程上执行是安全的,不需要添加额外的锁

等待操作

会阻塞当前线程

优先级

优先级只对当前队列有效。不同队列中的操作,低优先级有可能比高优先级先执行。优先级不能改变依赖关系

添加依赖和 waitUntilFinished 顺序错误会导致死循环

NSBlockOperation *blockOperation1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"1--%@",[NSThread currentThread]);
    }];
    NSBlockOperation *blockOperation2 = [NSBlockOperation blockOperationWithBlock:^{
        [blockOperation1 waitUntilFinished];
        NSLog(@"2--%@",[NSThread currentThread]);
    }];
    
    NSOperationQueue *queue1 = [[NSOperationQueue alloc] init];
    [blockOperation1 addDependency:blockOperation2];
    [queue1 addOperation:blockOperation2];
    [queue1 addOperation:blockOperation1];

解释:
首先在没有等待的时候你,队列的执行执行操作按照依赖顺序执行,如果没有依赖则按照添加到队列的顺序执行。
这里既有了等待,又又了依赖。此处,blockOperation2等待blockOperation1执行完成,然而blockOperation1又依赖于blockOperation2所以,死循环了。

自定义非并发

XSYOperation.h

#import 

NS_ASSUME_NONNULL_BEGIN

@interface XSYOperation : NSOperation

@end

XSYOperation.m

#import "XSYOperation.h"

@implementation XSYOperation

/*
 For non-concurrent operations, you typically override only one method:
 main
 */

- (void)main {
    
   @autoreleasepool {
       
       BOOL isDone = NO;
       while(![self isCancelled] && !isDone)
       {
           //在这里执行自己的任务操作
           NSLog(@"执行自定义非并发NSOperation");
           NSThread *thread = [NSThread currentThread];
           NSLog(@"%@",thread);
           //任务执行完成后将isDone设为YES
           isDone = YES;
       }
   }
}

@end

自定义并发

XSYConcurrentOperation.h

#import 

NS_ASSUME_NONNULL_BEGIN

@interface XSYConcurrentOperation : NSOperation {
    BOOL executing;
    BOOL finished;
}

@end

NS_ASSUME_NONNULL_END

XSYConcurrentOperation.m

#import "XSYConcurrentOperation.h"

/*
 If you are creating a concurrent operation, you need to override the following methods and properties at a minimum:
 start
 asynchronous
 executing
 finished
 */
@implementation XSYConcurrentOperation

- (instancetype)init {
    self = [super init];
    if (self) {
        executing = NO;
        finished = NO;
    }
    return self;
}

- (void)start {
    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"];
}

- (BOOL)isConcurrent {
    return YES;
}

- (BOOL)isExecuting {
    return executing;
}

- (BOOL)isFinished {
    return finished;
}

- (void)main {
    @autoreleasepool {
        //任务执行完成后要实现相应的KVO
        [self willChangeValueForKey:@"isFinished"];
        [self willChangeValueForKey:@"isExecuting"];
        
        executing = NO;
        finished = YES;
        
        [self didChangeValueForKey:@"isExecuting"];
        [self didChangeValueForKey:@"isFinished"];
    }
}

@end

你可能感兴趣的:(NSOperation)