NSOperation與GCD

NSOperation 抽象類
    - NSInvocationOperation
    - NSBlockOperation
 NSOpeartionQueue

 * GCD 的核心概念:將任務(block)添加到隊列,並且指定執行任務的函數
 * OP 的核心概念:將`操作`添加到`隊列`

NSInvocationOperation(不常用)


// 將操作添加到隊列 - 會異步執行操作!

- (void)opDemo1 {

    NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo:) object:@"invocation"];

    // start 會在當前線程執行 selector 方法,不會開啓線程
//    [op start];

    // 隊列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    // 將操作添加到隊列 - 會`異步`執行操作!
    [queue addOperation:op];
}

隊列是一個併發隊列

- (void)opDemo2 {
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    for (int i = 0; i < 100; ++i) {
        NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo:) object:@(i)];

        [queue addOperation:op];
    }
}
- (void)demo:(id)obj {
    NSLog(@"%@ %@", [NSThread currentThread], obj);
}

NSBlockOperation(常用)


任務在子線程異步併發執行

- (void)opDemo3 {
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    // 操作
    // 使用 block 所有的代碼可以在一起,便於閱讀和維護
    for (int i = 0; i < 10; ++i) {
        NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"%@ %d", [NSThread currentThread], i);
        }];

        [queue addOperation:op];
    }
}

將任務加入到一個全局隊列, 並且NSOperation的所有子類都可以加入, 異步執行

- (void)opDemo4 {
    for (int i = 0; i < 10; ++i) {
        [self.queue addOperationWithBlock:^{
            NSLog(@"%@ %d", [NSThread currentThread], i);
        }];
    }

    // BLOCK OPERATION
    // 所有的 NSOperation 的子類,都可以添加到隊列中
    // 並且都是異步執行的!
    NSBlockOperation *blockOp = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"BLOCK --- %@", [NSThread currentThread]);
    }];
    [self.queue addOperation:blockOp];

    NSInvocationOperation *inOp = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo:) object:@"INVOCATION"];
    [self.queue addOperation:inOp];
}

線程間通訊

- (void)opDemo5 {
    [self.queue addOperationWithBlock:^{
        NSLog(@"耗時的操作... %@", [NSThread currentThread]);

        // 在主線程更新UI 
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            NSLog(@"更新 UI %@", [NSThread currentThread]);
        }];
    }];
}

NSOperation的高級用法

  • 最大併發數
- (void)demo {
    // 設置最大併發的操作數
    [self.queue setMaxConcurrentOperationCount:2];

    NSLog(@"start");
    for (int i = 0; i < 20; ++i) {
        [self.queue addOperationWithBlock:^{

            [NSThread sleepForTimeInterval:1.0];

            NSLog(@"%@ %d", [NSThread currentThread], i);
        }];
    }
}

// 執行結果是兩個兩個一起來

  • 暫停/繼續
// 暫停繼續
- (IBAction)pauseAndResume {

    // 如果隊列是掛起的,再添加操作,也不會調度!
    // 判斷隊列中是否有操作
    if (self.queue.operationCount == 0) {
        NSLog(@"沒有操作");
        return;
    }

    // setter = !getter
    // 掛起的是隊列,不會影響正在執行的操作
    self.queue.suspended = !self.queue.isSuspended;

    // 如果隊列中的操作沒有執行完成,操作`計數`中是包含的
    if (self.queue.isSuspended) {
        NSLog(@"暫停 - %tu", self.queue.operationCount);
    } else {
        NSLog(@"繼續 - %tu", self.queue.operationCount);
    }
}

執行結果: 暫停的是隊列中的操作, 如果任務在線程中正在執行, 不會停止

  • 取消全部
- (IBAction)cancelAll {

    // 取消`隊列`中沒有調度的全部操作,如果正在執行的操作,不會被取消
    // 提示:如果要讓正在執行的操作取消,需要自定義操作,系統提供的不行!
    NSLog(@"取消全部");
    [self.queue cancelAllOperations];
}

執行結果: 系統提供的無法取消線程中正在執行的操作, 只能取消隊列中等待的操作.

  • 依賴關係(GCD中的依賴,可以用同步執行,barrier)
- (void)dependency {

    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"用戶登錄 %@", [NSThread currentThread]);
    }];
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"付費 %@", [NSThread currentThread]);
    }];
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"下載 %@", [NSThread currentThread]);
    }];
    NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"通知用戶 %@", [NSThread currentThread]);
    }];

    // 設置依賴關係 - 併發效率比GCD的串行隊列要好!
    // 依賴關係,可以跨隊列指定!
    // 付費需要在用戶登錄之後執行
    [op2 addDependency:op1];
    [op3 addDependency:op2];
    [op4 addDependency:op3];

    // waitUntilFinished NO 異步 YES 同步
    [self.queue addOperations:@[op1, op2, op3] waitUntilFinished:NO];

    // 向主隊列添加操作
    [[NSOperationQueue mainQueue] addOperation:op4];

    NSLog(@"come here");
}

GCD與NSOperation對比

  • GCD

將任務(block)添加到隊列(串行/併發/主隊列),並且指定任務執行的函數(同步/異步)
GCD是底層的C語言構成的API
iOS 4.0 推出的,針對多核處理器的併發技術
在隊列中執行的是由 block 構成的任務,這是一個輕量級的數據結構
要停止已經加入 queue 的 block 需要寫複雜的代碼
需要通過 Barrier 或者同步任務設置任務之間的依賴關係
只能設置隊列的優先級
高級功能:
一次性 once
延遲操作 after
調度組

  • NSOperation

核心概念:把操作(異步)添加到隊列(全局的併發隊列)
OC 框架,更加面向對象,是對 GCD 的封裝
iOS 2.0 推出的,蘋果推出 GCD 之後,對 NSOperation 的底層全部重寫
Operation作爲一個對象,爲我們提供了更多的選擇
可以隨時取消已經設定要準備執行的任務,已經執行的除外
可以跨隊列設置操作的依賴關係
可以設置隊列中每一個操作的優先級
高級功能:
最大操作併發數(GCD不好做)
繼續/暫停/全部取消
跨隊列設置操作的依賴關係

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