iOS 多線程之NSOperation篇舉例詳解


  這篇博客是接着總篇iOS GCD NSOperation NSThread等多線程各種舉例詳解寫的一個支篇。總篇也包含了此文的鏈接。本文講解的知識點有NSBlockOperationClick,隊列,隊列中如何加Operation,Operation中如何加任務,Operation之間的串行、並行,監控任務完成時機及其他一些關於NSOperation的方法,每個知識點都有例子和詳細分析。附上demo下載地址

一、NSOperation介紹

  NSOperation 是蘋果公司對 GCD 的封裝,完全面向對象。NSOperation實例封裝了需要執行的操作和執行操作所需的數據,並且能夠以並發或非並發的方式執行這個操作。NSOperation本身是抽象基類,因此可以使用它的子類NSInvocationOperation 和 NSBlockOperation,或者自定義子類也行。NSOperation 和 NSOperationQueue 可以看成是GCD的任務和隊列。

二、NSInvocationOperation(不是類型安全的,蘋果在swift里不用它了)

  但是我還是來講講,證明它曾經存在過。NSInvocationOperation創建一個 Operation 后,需要調用 start 方法來啟動任務,它會 默認在當前隊列同步執行。舉個例子

- (IBAction)NSInvocationOperationClick:(id)sender {
    //1.創建NSInvocationOperation對象
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(myTask) object:nil];
    operation.completionBlock = ^() {
        NSLog(@"執行完畢");
    };
    //2.在當前線程執行
    [operation start];
    NSLog(@"阻塞我沒有?當前線程%@",[NSThread currentThread]);
}

//模擬很耗時的任務
-(void)myTask {
    for (NSInteger i = 0; i < 500000000; i++) {
        if (i == 0) {
            NSLog(@"任務 -> 開始");
        }
        if (i == 499999999) {
            NSLog(@"任務 -> 完成");
        }
    }
}

 

打印結果:

分析結論:從打印結果看,會阻塞當前線程,因為他是同步執行的。

三、NSBlockOperationClick

  在block中加任務,使用更方便,代碼更緊湊,舉個例子。

- (IBAction)NSBlockOperationClick:(id)sender {
    //1.創建NSBlockOperation對象
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        [self myTask];
    }];
    
    //2.也可以添加多個Block,通過這個方法可以給 Operation 添加多個執行 Block。這樣 Operation 中的任務 會並發執行,它會 在主線程和其它的多個線程 執行這些任務
    for (NSInteger n = 0; n < 3; n++) {
        [operation addExecutionBlock:^{
            for (NSInteger i = 0; i < 500000000; i++) {
                if (i == 0) {
                    NSLog(@"任務%ld -> 開始",n);
                }
                if (i == 499999999) {
                    NSLog(@"任務%ld -> 完成",n);
                }
            }
        }];
    }
    operation.completionBlock = ^() {
        NSLog(@"執行完畢");
    };
    //3.開始任務
    [operation start];
    NSLog(@"阻塞我沒有?當前線程%@",[NSThread currentThread]);
}

打印結果:

分析結論:給 Operation 添加多個執行 Block任務,Operation 中的任務會並發執行,它會在主線程和其它的多個線程執行這些任務,會阻塞當前主線程。

四、主隊列

  舉個例子

//主隊列里的任務並行執行,且不阻塞當前線程。(隊列中加多個operation時另說,看第五個例子就知道了)
- (IBAction)mainQueue:(id)sender {
    NSOperationQueue *queue = [NSOperationQueue mainQueue];
    //創建NSBlockOperation對象
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        [self myTask];
    }];
    for (NSInteger n = 0; n < 3; n++) {
        [operation addExecutionBlock:^{
            for (NSInteger i = 0; i < 500000000; i++) {
                if (i == 0) {
                    NSLog(@"主隊列中任務%ld -> 開始%@",n,[NSThread currentThread]);
                }
                if (i == 499999999) {
                    NSLog(@"主隊列中任務%ld -> 完成",n);
                }
            }
        }];
    }
    operation.completionBlock = ^() {
        NSLog(@"執行完畢");
    };
    //加入到隊列中任務自動執行
    [queue addOperation:operation];
    NSLog(@"阻塞我沒有?當前線程%@",[NSThread currentThread]);
}

打印結果:

分析結論:主隊列里的任務都是另開線程並行執行的,不會阻塞當前線程。(隊列中加多個operation時另說,請看下面例子)

五、其他隊列

  基本用法跟主隊列差不多,我將在這個例子里列舉更多用法。在一個隊列里加2個operation,第一個operation里加2個任務。舉個例子

- (IBAction)otherQueue:(id)sender {
    //1.創建一個其他隊列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    //最大並發數,用來設置最多可以讓多少個operation同時執行。當你把它設置為 1 的時候,就是串行了(指多個operation的串行,同一個operation中的任務是並行的)
    queue.maxConcurrentOperationCount = 1;
    
    //2.創建NSBlockOperation對象
    NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
        for (NSInteger i = 0; i < 500000000; i++) {
            if (i == 0) {
                NSLog(@"operation1中任務1 -> 開始");
            }
            if (i == 499999999) {
                NSLog(@"operation1中任務1 -> 完成");
            }
        }
    }];
    
    //3.給operation1再加一個任務
    [operation1 addExecutionBlock:^{
        for (NSInteger i = 0; i < 500000000; i++) {
            if (i == 0) {
                NSLog(@"operation1中任務2 -> 開始");
            }
            if (i == 499999999) {
                NSLog(@"operation1中任務2 -> 完成");
            }
        }
    }];
    operation1.completionBlock = ^() {
        NSLog(@"執行完畢");
    };
    
    //4.再加一個operation2
    NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
        for (NSInteger i = 0; i < 500000000; i++) {
            if (i == 0) {
                NSLog(@"operation2中任務 -> 開始");
            }
            if (i == 499999999) {
                NSLog(@"operation2中任務 -> 完成");
            }
        }
    }];
    
    //5.加入到隊列中任務自動執行,waitUntilFinished為yes會阻塞當前線程,為no不阻塞
    [queue addOperations:@[operation1,operation2] waitUntilFinished:NO];
    NSLog(@"阻塞我沒有?當前線程%@",[NSThread currentThread]);
}

打印結果:

分析結論:2個operation是串行的,但同一個operation中的多個任務是並行的

六、任務依賴

  任務一完成的情況下才能執行任務二,任務二完成的情況下才能執行任務三,舉個例子。

//任務依賴
- (IBAction)addDependency:(id)sender {
    //1.任務一
    NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"任務1開始");
        [NSThread sleepForTimeInterval:1.0];
        NSLog(@"任務1完成");
    }];
    //2.任務二
    NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"任務2開始");
        [NSThread sleepForTimeInterval:1.0];
        NSLog(@"任務2完成");
    }];
    //3.任務三
    NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"任務3開始");
        [NSThread sleepForTimeInterval:1.0];
        NSLog(@"任務3完成");
    }];
    //4.設置依賴
    [operation2 addDependency:operation1];      //任務二依賴任務一
    [operation3 addDependency:operation2];      //任務三依賴任務二
    //5.創建隊列並加入任務
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperations:@[operation3, operation2, operation1] waitUntilFinished:NO];
}

打印結果:

分析結論:該任務依賴的任務完成了,才能執行該任務。

七、其他相關方法

// 暫停queue
[queue setSuspended:YES];

// 繼續queue
[queue setSuspended:NO];
 //會阻塞當前線程,等到某個operation執行完畢
[operation waitUntilFinished];
// 阻塞當前線程,等待queue的所有操作執行完畢
[queue waitUntilAllOperationsAreFinished];
// 取消單個操作
[operation cancel];
// 取消queue中所有的操作
[queue cancelAllOperations];

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM