iOS開發之多線程-- NSOperation使用簡介(個人筆記)

 NSOperation使用簡介  

1.操作 NSOperation 和操作隊列 NSOperationQueue!

{

    1.NSOperation(操作)簡介:

    

    NSOperation: // 本質是對 GCD 的封裝, OC 語言.

    

    NSOperation GCD 的比較:

    

    GCD使用場合:

    一些簡單的需求,簡單的多線程操作. //簡單高效

    

    NSOperation使用場合:

    各個操作之間有依賴關係,操作需要取消/暫停;需要限制同時執行的線程數量,讓線程在某時刻停止/繼續等.

    

    配合使用 NSOperation NSOperationQueue 也可以實現多線程.


    2.NSOperation使用:

    

    NSOperation: 抽象類,不能直接使用,需要使用其子類.

    

    抽象類:定義子類共有的屬性和方法.// CAAnimation/CAPropertyAnimation...

    

    兩個常用子類: NSInvocationOperation(調用) NSBlockOperation();

    

                兩者沒有本質區別,後者使用 Block 的形式組織代碼,使用相對方便.

    

    自定義子類繼承自 NSOperation,實現內部相應的方法. // 高級用法

}

2.NSBlockOperation, NSInvocationOperation的簡單使用.

{

    1. 創建 NSInvocationOperation 對象

    

    // 創建 NSInvocationOperation

    NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(longTimeOperation:) object:@"op1"];

    

    //默認情況下,調用 start 方法之後,不會開啓新線程,只會在當前線程執行操作.

    [op1 start];

    

    注意:只有將 NSOperation 放到一個 NSOperationQueue ,纔會異步執行操作.

    

    2. 創建 NSBlockOperation 對象

    

    // 創建 NSBlockOperation

    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"下載圖片1---%@",[NSThread currentThread]);

    }];

    // 添加更多操作

    [op2 addExecutionBlock:^{

        NSLog(@"下載圖片2---%@",[NSThread currentThread]);

    }];

    [op2 addExecutionBlock:^{

        NSLog(@"下載圖片3---%@",[NSThread currentThread]);

    }];

    

    // 只要 NSBlockOperation 中封裝的操作數 > 1, 調用start方法之後就會開啓多條線程併發執行

    // 如果 NSBlockOperation 中封裝的操作數 == 1,調用 start 方法之後,不會開啓新線程,只會在當前線程執行操作

    [op2 start];

    

    注意: 只要 NSBlockOperation 中封裝的操作數 > 1,就會異步執行這些操作.(將操作添加到 NSOperationQueue中或者直接調用 start方法都會開啓多條線程異步執行).

}

3.將操作添加到隊列中;

{

    NSOperation 可以調用 start 方法來執行任務,但默認是同步執行的.

    NSOperation 添加到 NSOperationQueue(操作隊列) ,系統會自動異步執行NSOperationQueue中的操作.

    

    1.NSOperationQueue(操作隊列):

    

    <1> 主隊列

    [NSOperationQueue mainQueue] //獲取主隊列

    添加到"主隊列"中的操作,都會放在主線程執行!

    

    <2>非主隊列

    [[NSOperationQueue alloc] init]; //創建非主隊列

    添加到"非主隊列"中得操作,都會放在子線程中執行.

    

    2.使用: 添加操作到操作隊列中.

    

    // 創建 NSInvocationOperation 操作

    NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(longTimeOperation:) object:@"op1"];

    

    // 創建 NSBlockOperation 操作

    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"下載圖片1---%@",[NSThread currentThread]);

    }];


    // 1.創建一個 NSOperationQueue

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    

    // 2.將操作添加到隊列中.

    [queue addOperation:op1];

    [queue addOperation:op2];

    

    注意:另外一種添加操作到隊列中的方法: block

    [queue addOperationWithBlock:^{

        NSLog(@"下載圖片5---%@",[NSThread currentThread]);

    }];

    

    推薦使用: block // 簡單. 自己哪個使用熟練就用哪個.

    

    注意:隊列中任務的執行是無序的.

    

}

 4.常見用法 

1.設置操作依賴. 2.設置最大併發數.

{

    問題:是否可以讓隊列中的操作有序執行?

    

    回答上問題: ,設置操作依賴.

    

    1.NSOperation設置操作依賴: // 執行順序: op1,op2,op3;

    

    // 操作op3依賴於操作op2;

    [op3 addDependency:op2];

    // 操作op2依賴於操作op1;

    [op2 addDependency:op1];

    

    注意:不能相互依賴.

    

    2.NSOperationQueue設置最大併發數.

    

    併發數:同時開啓的線程數.

    

    // 創建操作隊列

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    // 設置操作隊列的最大併發數

    queue.maxConcurrentOperationCount = 3;

    [queue setMaxConcurrentOperationCount:3];

}


1.隊列的取消/暫停/恢復  2.線程間通信. 注意問題:爲毛要取消/恢復隊列? 在什麼時候用?

{

    1.NSOperationQueue 的取消/暫停/恢復

    

    // 取消操作 op1. 取消單個操作.

    [op1 cancel];

    // 取消所有操作,不會再次恢復

    [queue cancelAllOperations];

    // 暫停所有操作;注意,已經開始的操作不會暫停.

    [queue setSuspended:YES];

    // 重新開始所有操作

    [queue setSuspended:NO];

    

    :爲毛要取消恢復隊列? 在什麼時候用?

    

    :1.爲了內存管理,處理內存警告; 2.爲了用戶體驗,保證滾動流暢.

    

    // 接收到內存警告的時候果斷取消隊列中的所有操作

    - (void)didReceiveMemoryWarning

    {

        [super didReceiveMemoryWarning];

        

        [queue cancelAllOperations]; // 取消隊列中的所有任務(不可恢復)

    }

    // 開始滾動的時候暫停隊列中的任務.

    - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView

    {

        [queue setSuspended:YES]; // 暫停隊列中的所有任務

    }

    // 滾動結束的時候恢復隊列中的任務.

    - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate

    {

        [queue setSuspended:NO]; // 恢復隊列中的所有任務

    }


    2.線程間通信  // 子線程下載圖片,主線程設置圖片.

    

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    

    [queue addOperationWithBlock:^{

        // 1.異步下載圖片

        NSURL *url = [NSURL URLWithString:@"http://d.hiphotos.baidu.com/image/pic/item/37d3d539b6003af3290eaf5d362ac65c1038b652.jpg"];

        NSData *data = [NSData dataWithContentsOfURL:url];

        UIImage *image = [UIImage imageWithData:data];

        

        // 2.回到主線程,顯示圖片

        [[NSOperationQueue mainQueue] addOperationWithBlock:^{

            self.imageView.image = image;

        }];

    }];

    

}

// 定義一個全局的隊列屬性.方便在任何方法中都可以使用這個Queue

@property (nonatomic,strong) NSOperationQueue *queue;


// UI 控件用 weak Strong 都沒有問題.

// 在開發中,基本會見到所有的UI控件都是用 Strong來做的.

// UI控件一般不要用懶加載的方式加載.UI控件與用戶是對應的.UI控件之外的,能用懶加載就用懶加載.

@property (nonatomic,strong) UIButton *button;


// 設置最大併發數.最多同時只能開啓6條線程.

[_queue setMaxConcurrentOperationCount:6];

// 這裏直接在Block 中使用 self 會造成循環引用. Block使用的注意點之一:循環引用.

//  __weak typeof(self) wself = self; wself 就是 self 的弱引用寫法.


// GCD中的任務都是封裝在Block,如果GCD中的Block中出現了 self,會造成循環引用嗎?

//


//    dispatch_async(dispatch_get_main_queue(), ^{

//        [self test];

//    }); 會造成循環引用嗎? 不會造成循環引用,因爲 self 對這個Block 沒有強引用.


// 創建操作

__weak typeof(self) wself = self;

NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{

    

    // Block中出現self .Block self 是強引用.

    [wself test];

}];


// 將操作添加到隊列中.

// self.queue op 就是強引用.

[self.queue addOperation:op];



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章