Operation與GCD的不一樣

最大併發數:ios

什麼是併發數?併發

同時執行的任務數。好比同時開啓三個線程執行三個任務,併發數就是3.app

最大併發數相關的方法:異步

-(NSInteger)maxConcurrentOperationCount;ide

-(void)setMaxConcurrentOperationCount:(NSInteger)cnt;atom

剖析最大併發數:併發數就是同時執行操做的數量,並非只線程的個數。就是指同時執行任務的個數,當一個線程執行完畢後會有一個回收到線程池的過程,這時若是線程池中還有別的線程就會直接拿出來進行任務的執行。若是線程池中沒有線程,就會等待回收後的線程。spa

注:最大線程個數是由CPU內核決定的線程

GCD與NSOPeration的線程的不一樣之處code

1。咱們知道GCD的線程大致可分爲六大中,同步串行隊列(不開闢線程),同步並行隊列(開闢線程),異步串行隊列(開闢線程),異步並行隊列(開闢線程),主隊列, 全局隊列。對象

    可是咱們知道開闢線程和耗費內存,而GCD中方法雖多,可是不少咱們開闢線程並無意義,反而會耗費內存。NSOPeration實際上是對GCD中的一個封裝,可是他並無封裝GCD中全部的方法。NSOperationQueue建立出來的對象至關於異步並行隊列,NSInvocationOperation若有start這至關於同步串行隊列。NSBlockOperation將建立的對象加到NSOperationQueue建立隊列中,至關一異步串行

 NSOperationQueue * q = [NSOperationQueue mainQueue]至關於GCD的主隊列

 

2.隊列的取消、暫停、和恢復NSOPeration有,GCD是沒有的

取消隊列的全部操做

-(void)cancelAllOperations;

提示:也能夠調用NSOperation的-(void)cancel方法取消單個操做。

暫停和恢復隊列

-(void)setSuspended:(BOOL)b; // YES表示暫停隊列 NO表示恢復隊列

-(BOOL)isSuspend;

獲取隊列操做數:

operationCount(只讀屬性)

注意:

(1)暫停不會刪除隊列內的操做。只是把隊列掛起。暫停和掛起都是針對隊列而言的。暫停後還能夠從新恢復接着原來的任務進行執行。

(2)取消所有任務的操做會清空隊列裏的全部任務。

(3)暫停和取消都是對隊列裏的操做而言的,而正在執行的操做是沒法取消或暫停的。

在實際的開發中:一般定義一個全局的操做隊列, 而後就能夠把全部的任務都添加進去。在開發中須要注意的兩點:

(1)在用戶點擊」暫停/繼續」的按鈕觸發的事件中,須要先判斷當前隊列內是否有任務,若是全局隊列內沒有任務就直接return返回,從而沒有任務的時候不會改變隊列的掛起和恢復狀態。

(2)在用戶點擊」取消所有操做」的按鈕觸發的事件中,取消操做以後須要重置全局隊列爲恢復狀態,這樣無論原先全局隊列的狀態如何,在取消所有操做以後又從新置於初始狀態。從而不會影響新的操做。

 代碼

- (void) viewDidLoad
{
    self.view.backgroundColor = [UIColor whiteColor];
    
    UIButton * downButton = [UIButton buttonWithType:UIButtonTypeCustom];
    downButton.frame = CGRectMake(20, 80, 200, 60);
    [downButton setBackgroundColor:[UIColor greenColor]];
    [downButton addTarget:self action:@selector(download) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:downButton];
}

- (void) download
{
    if (self.opQueue.operationCount == 0) {
        NSLog(@"沒有操做");
        return;
    }
    //暫停,繼續
    self.opQueue.suspended = !self.opQueue.suspended;
    if (self.opQueue.suspended) {
        NSLog(@"暫停");
    }
    else
    {
        NSLog(@"繼續");
    }

}
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//    [self opDemo1];
//    [self opDemo2];
//    [self opDemo3];
//    [self opDemo4];
    [self opDemo5];
}
//懶加載
- (NSOperationQueue *)opQueue
{
    if(_opQueue == nil)
    {
        _opQueue = [[NSOperationQueue alloc] init];
    }
    return _opQueue;
    
}

#pragma mark - 線程間通訊
- (void) opDemo5
{ 
    self.opQueue = [[NSOperationQueue alloc] init];
//maxConcurrentOperationCount 必需要設,否者暫停不了
//我的理解,若不設置最大併發數,則全部任務併發執行,而暫停操做只能暫停還沒開始的任務。下載中的任務不會暫停
//maxCincurrentOpertaionCount爲多少,暫停下載後。就會有多少任務下載完成,由於點擊暫停時,還有這麼多人物在執行中 self.opQueue.maxConcurrentOperationCount
= 1; NSLog(@"+1"); for (int i = 0; i < 500; i ++) { NSOperation * op = [NSBlockOperation blockOperationWithBlock:^{ [NSThread sleepForTimeInterval:1]; NSLog(@"%d 耗時操做 ===== %@", i,[NSThread currentThread]); }]; [self.opQueue addOperation:op]; } NSLog(@"+3"); }

 NSOperation之間能夠設置依賴來保證執行順序,這是GCD所不具有的功能:

好比必定要讓操做A執行完後,才能執行操做B,能夠這麼寫:

[operationB addDependency:operationA];  // 操做B依賴於操做

 - 具體使用:將任務(block)添加到隊列(串行/併發(全局)),指定執行任務的方法(同步(阻塞)/異步)

 - 線程通訊:獲取主線程dispatch_get_main_queue()。在主線程更新UI

 -  還有NSOperation沒法作到的事:一次性執行,延遲執行,調度組(NSOperation相對複雜)

 NSOperation ---->ios2.0(後來改造了NSOperation的底層)

 - 具體使用:將操做(異步執行的)添加到隊列(併發/全局)。其實就是封裝了GCD裏的異步執行全局或併發隊列。

 - 線程通訊: [[NSOperationQueue mainQueue] addOperation:op3];拿到主隊列,往主隊列添加操做(更新UI)

 - 提供了一些GCD沒法實現的功能:最大併發數」 

 - 暫停/繼續 -------掛起

 - 取消全部任務

 - 依賴關係

  1 <span style="font-size:18px;">//
  2 //  ViewController.m
  3 //  NSOperation之線程間通訊
  4 //
  5 //  Created by apple on 15/10/22.
  6 //  Copyright (c) 2015年 LiuXun. All rights reserved.
  7 //
  8 
  9 #import "ViewController.h"
 10 
 11 @interface ViewController ()
 12 /**
 13  通常開發中,會定義一個全局的隊列。整個程序均可以把操做往裏面放。
 14  負責調度全部的操做
 15  */
 16 @property(nonatomic, strong) NSOperationQueue *opQueue;
 17 @end
 18 
 19 @implementation ViewController
 20 
 21 /**
 22  小結:
 23  只要是NSOperation的子類,就能添加到操做隊列
 24  - 一旦操做添加到隊列, 就會自動異步執行
 25  - 若是沒有添加到隊列, 而是使用start方法,就會在當前線程執行操做
 26  - 若是是線程間通訊, 可使用[NSOperaionQueue mainQueue] 拿到主隊列,往主隊列添加操做(更新UI)
 27  */
 28 
 29 /**
 30  GCD----> ios4.0
 31  - 具體使用:將任務(block)添加到隊列 (串行/併發(全局)) ,指定執行任務的方法(同步(阻塞)/異步)
 32  - 線程通訊:獲取主線程dispatch_get_main_queue()。在主線程更新UI
 33  -  還有NSOperation沒法作到的事:一次性執行,延遲執行,調度組(NSOperation相對複雜)
 34  
 35  NSOperation ---->ios2.0 (後來改造了NSOperation的底層)
 36  - 具體使用:將操做(異步執行的)添加到隊列(併發/全局)。其實就是封裝了GCD裏的異步執行全局或併發隊列。
 37  - 線程通訊: [[NSOperationQueue mainQueue] addOperation:op3];拿到主隊列,往主隊列添加操做(更新UI)
 38  - 提供了一些GCD沒法實現的功能:「最大併發數」
 39  - 暫停/繼續 ------- 掛起
 40  - 取消全部任務
 41  - 依賴關係
 42  */
 43 
 44 /**
 45  懶加載的方式,初始化NSOperationQueue對象
 46  */
 47 -(NSOperationQueue *)opQueue
 48 {
 49     if(_opQueue == nil)
 50     {
 51         _opQueue = [[NSOperationQueue alloc] init];
 52     }
 53     return _opQueue;
 54 }
 55 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
 56 {
 57     [self dependcy];
 58 }
 59 #pragma mark - 線程間通訊(很是重要)
 60 -(void)opDemo1
 61 {
 62     NSOperationQueue *q = [[NSOperationQueue alloc] init];
 63     [q addOperationWithBlock:^{
 64         NSLog(@"耗時操做......%@", [NSThread currentThread]);
 65         
 66         // 在主線程更新UI
 67         [[NSOperationQueue mainQueue] addOperationWithBlock:^{
 68             NSLog(@"更新UI......%@", [NSThread currentThread]);
 69         }];
 70     }];
 71 }
 72 
 73 #pragma mark- 最大併發數
 74 /**
 75  注意:最大併發數不是說線程的數量,而是說同時進行操做的數量
 76  */
 77 -(void)opDemo2
 78 {
 79     self.opQueue.maxConcurrentOperationCount = 2;
 80     for(int i=0; i<10 ; i++){
 81         NSOperation *op = [NSBlockOperation blockOperationWithBlock:^{
 82             [NSThread sleepForTimeInterval:1.0];
 83             NSLog(@"%@------%d", [NSThread currentThread], i);
 84         }];
 85         [self.opQueue addOperation:op];
 86     }
 87 }
 88 
 89 #pragma mark - 高級操做  掛起
 90 // 就是暫停和繼續:  對隊列的操做
 91 /**
 92  應用場景:好比當咱們在有WiFi的地發用手機下載電影,可是有事情走開了,斷網了電影只下載了一半,這時就須要掛起,等到了有網的地方又能夠接着原來的進度下載。
 93  切記:掛起的是隊列,不會影響已經在執行的操做
 94  */
 95 -(IBAction)pause
 96 {
 97     
 98     // 判斷操做的數量,當前隊列裏面是否有操做
 99     if(self.opQueue.operationCount == 0){
100         NSLog(@"沒有操做");
101         return; // 沒有操做的時候直接return,不會修改隊列的狀態
102     }
103     
104     // 暫停繼續 :
105     self.opQueue.suspended = !self.opQueue.suspended;
106     if(self.opQueue.suspended){
107         NSLog(@"暫停");
108     }else
109     {
110         NSLog(@"繼續");
111     }
112 }
113 
114 #pragma mark- 高級操做 隊列取消
115 /**
116  取消操做並不會影響隊列的掛起狀態
117  */
118 -(IBAction)cancel
119 {
120     // 取消隊列內的全部操做
121     // 只是取消隊列裏的任務,而正在執行的任務是沒法取消的
122     // 另外取消了任務就是刪除了隊列內的全部操做
123     [self.opQueue cancelAllOperations];
124     NSLog(@"取消全部操做");
125     
126     // 取消隊列的掛起狀態(只要是取消了隊列的操做,咱們就把隊列處於一個啓動狀態,以便於後續的開始)
127     self.opQueue.suspended = NO;
128 }
129 
130 #pragma mark -依賴關係
131 -(void)dependcy
132 {
133     /**
134      舉例場景:
135      1. 下載一個小說的壓縮包
136      2. 解壓縮,刪除壓縮包
137      3. 更新UI
138      */
139     NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
140         NSLog(@"下載一個小說的壓縮包,%@",[NSThread currentThread]);
141     }];
142     NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
143         NSLog(@"解壓縮,刪除壓縮包,%@",[NSThread currentThread]);
144     }];
145     NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
146         NSLog(@"更新UI,%@",[NSThread currentThread]);
147     }];
148     // 若是直接把任務添加到隊裏,會異步執行,使順序錯亂
149     
150     // 所以須要指定任務之間的依賴關係--------依賴關係能夠跨隊列(能夠在子線程下載完,到主線程更新UI)
151     [op2 addDependency:op1];  // op2 依賴於op1  就是執行op2以前必須先執行op1
152     [op3 addDependency:op2];  // op3 依賴於op2  就是執行op3以前必須先執行op2
153     
154     /**
155      千萬注意:不要形成相互依賴即依賴循環,會形成死鎖
156      */
157     //    [op1 addDependency:op3];
158     
159     
160     // waitUntilFinished 相似於GCD中調度組的通知
161     // NO表示不等待當前的隊列執行完畢,就執行下面的代碼,打印 NSLog(@"任務完成");
162     // YES 表示必須等隊列內的任務所有執行完畢才執行下面的代碼
163     [ self.opQueue addOperations:@[op1, op2] waitUntilFinished:YES];
164     
165     // 在主線程更新UI
166     [[NSOperationQueue mainQueue] addOperation:op3];
167     
168     NSLog(@"任務完成");
169 }
170 @end
171 </span>
相關文章
相關標籤/搜索