SDWebimage相关知识点1-- NSOperation

GCD      
GCD是最经常使用的管理并行代码和执行异步操做的Unix系统层的API。GCD构造和管理队列中的任务。
 
队列是按先进先出(FIFO)管理对象的数据结构。队列相似电影院的售票窗口,票的销售是谁先到谁先服务。在等待线前面的人先去买他们的门票,在其他的后抵达的人以前。队列在计算机科学中是类似的,由于第一个添加到队列的对象也是第一个从队列中删除的对象。
 
 
操做队列  NSOperationQueue
 
GCD是一个底层的C的API,它使开发人员可以并行地执行任务。操做队列,另外一方面,是高度抽象的队列模型,是创建在GCD之上的。这意味着你能够并行执行任务就像GCD同样,但以面向对象的方式。简而言之,队列操做让编程更加简单。
 
不一样于GCD,它们不按先进先出的顺序。下面是操做队列和调度队列的不一样点:
 
1.不遵循先进先出:在操做队列中,你能够设置一个操做的执行优先级,你能够添加操做之间的依赖关系,这意味着你能够定义一些操做完成后才会执行其余操做。这就是为何它们不遵循先进先出。
2.默认状况下,它们同时操做:然而你不能把它的类型改变成串行队列。经过使用操做之间的依赖关系,在操做队列还存在一个工做区来依次执行任务。
3.操做队列是类NSOperationQueue的实例,其任务封装在NSOperation的实例里。
 
 
NSOperation
 
是苹果提供的一套多线程解决方案,实际上NSOperation是基于GCD 更高一层的封装,可是比GCD 更简单易用、代码可读性更高。 
 
须要配合NSOperationQueue 来实现多线程。 默认状况下,单独使用NSOperation时系统执行同步操做,并无开辟新线程的能力,只有和配合NSOperationQueue 才能实现异步执行。 
 
由于NSOperation是基于GCD的,那么使用起来也和GCD差很少,其中,NSOperation至关于GCD中的任务,而NSOperationQueue则至关于GCD中的队列。NSOperation实现多线程的使用步骤分为三步:
  1. 建立任务:先将须要执行的操做封装到一个NSOperation对象中。
  2. 建立队列:建立NSOperationQueue对象。
  3. 将任务加入到队列中:而后将NSOperation对象添加到NSOperationQueue中。
以后呢,系统就会自动将NSOperationQueue中的NSOperation取出来,在新线程中执行操做。
 
NSOperation是一个抽象类,它不能直接使用,因此你必须使用NSOperation子类。在iOS SDK里,咱们提供两个NSOperation的具体子类。这些类能够直接使用,但你也能够继承NSOperation来建立本身的类来执行操做。咱们能够直接使用的两个类:
 
 
1.NSBlockOperation——使用这个类来用一个或多个block初始化操做。操做自己能够包含多个块。当全部block被执行操做将被视为完成。
 
2.NSInvocationOperation——使用这个类来初始化一个操做,它包括指定对象的调用selector。
 
或者定义继承自NSOperation的子类,经过实现内部相应的方法来封装任务。
 
NSOperationQueue
 
和GCD中的并发队列、串行队列不一样的是,NSOperationQueue 一共有两种队列:主队列、其余队列。 
其余队列中包含了串行、并发功能。 
 
NSOperationQueue *queue = [NSOperationQueue mainQueue];//主队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];//其余队列
 
将任务加入到队列中
1.先建立任务,再将建立好的任务加入到建立好的队列中去
- (void)addOperation:(NSOperation *)op;
 
2.无需建立任务,在block中执行任务,直接将任务block加入到队列中
(void)addOperationWithBlock:(void (^)(void))block;
 
 
控制串行执行和并发执行的关键
 
最大并发数:maxConcurrentOperationCount
默认状况下是-1,表示不进行限制,默认为并发执行。
当为1时,进行串行执行。
当>1时,进行并发执行。
 
 
操做依赖
NSOperation和NSOperationQueue最吸引人的地方是它能添加操做之间的依赖关系。好比说有A、B两个操做,其中A执行完操做,B才能执行操做,那么就须要让B依赖于A。
 
- (void)addDependency
 
一些其余的方法:
  • - (void)cancel; NSOperation提供的方法,可取消单个操做
 
 
  • - (void)cancelAllOperations; NSOperationQueue提供的方法,能够取消队列的全部操做
 
  • - (void)setSuspended:(BOOL)b; 可设置任务的暂停和恢复,YES表明暂停队列,NO表明恢复队列
 
  • - (BOOL)isSuspended; 判断暂停状态
 
 
注意:
这里的暂停和取消并不表明能够将当前的操做当即取消,而是当当前的操做执行完毕以后再也不执行新的操做
 
  • 暂停和取消的区别就在于:暂停操做以后还能够恢复操做,继续向下执行;而取消操做以后,全部的操做就清空了,没法再接着执行剩下的操做。
 
自定义子类:
 
使用main方法,不须要管理一些状态属性(如isExecuting 和 isFinished ),当main 方法返回的时候,这个operation 就结束了。 这种方式使用起来很是简单,main方法执行完就认为operation 结束了。因此通常能够用来执行同步任务。
 
若是你但愿拥有更多的控制权,或者想在一个操做中能够执行异步任务,那么就重写start 方法。 
在这种状况下,必须手动管理操做的状态,只有当发送isFinished 的kvo 消息时,才认为是operation 结束。
 

 
 
 
因此NSOperation的优点是什么?
 
1.首先,它们经过NSOperation类里的方法addDependency(op:NSOperation)支持依赖。当你须要开始一个依赖于其它操做执行的操做,你会须要NSOperation。
 
2.其次,你能够经过下面这些值设置属性queuePriority来改变执行优先级:
 
3.对于任何给定的队列,你能够取消一个特定的或全部的操做。操做能够在被添加到队列后被取消。取消是经过调用NSOperation类里的方法cancel()。当你取消任何操做的时候,咱们有三个场景,其中一个会发生:
你的操做已经完成。在这种状况下,取消方法没有效果。
你的操做已经被执行。在这种状况下,系统不会强制操做代码中止,而是属性cancelled被置为true。
你的操做仍在队列中等待。在这种状况下,你的操做将不会被执行。
 
4.NSOperation有3个有用的布尔属性,finished、 cancelled和ready。一旦操做执行完成,finisher将被置为true。一旦操做被取消,cancelled将被置为true。一旦准备即将被执行,ready将被置为true。
 
5.任何NSOperation有一个选项来设置回调,一旦任务完成将会被调用。在NSOperation里,一旦属性finished被置为true,这个block将被调用。
 
原理探析:
 
demo:
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    [self configurationQueue];
    LDNSOperation *operation = [[LDNSOperation alloc] init];
    [self.operationQueue addOperation:operation];
    [NSThread sleepForTimeInterval:3];
    [operation cancel];
    
}
 
-(void)configurationQueue{
    self.operationQueue = [[NSOperationQueue alloc] init];
    self.operationQueue.maxConcurrentOperationCount = 4;
}
 
LDNSOperation为NSOperation的子类,重写start方法:
-(void)start{
    while (true) {
        if(self.cancelled){
            NSLog(@"已经取消");
            return;
        }
        NSLog(@"start");
        [NSThread sleepForTimeInterval:1];
    }
}
 
 
1.
[self.operationQueue addOperation:operation];
 
添加一个未完成的NSOperation ,其实就是将NSOperation 添加到一个动态的数组中。 
 
 
internal 就是一个内部类,指的是NSOperationQueue 。
使用了KVO手动通知,进行operations 和 operationCount 的改变通知。
 
 
完成的话,就从operations 中删除。 
若是准备完成,就添加到waiting 中,等待被执行。 
 
_execute 方法:
 
 
若是没有暂停,就从waiting 中取出第一个,而且删除waiting 中的这个数据。 
添加isFinished 属性观察
若是是并发的话,就立刻执行。 
若是不是,使用detachNewThreadSelector来建立新的线程去执行start。
 
全部的线程都很忙,而且没有达到threadCount最大值时,会建立新的线程。 
_execute 是一个执行队列,依次将等待队列里全部的operation 进行start 。
 
对于start 函数来说,一个NSOperation 并无新建一个线程。 依然操做在[NSTread currentThread]中。 
 
如今来思考下,也就明白了为何NSOperationQueue要有两种处理方式了,若是NSOperation支持并发,而后NSOperationQueue在为其分配线程,那就是线程里面又跑了一条线程,这样就很尴尬了,经过isConcurrent能够避免这种现象。
相关文章
相关标签/搜索