1、簡介編程
(1) NSOperationQueue(操做隊列)是由GCD提供的隊列模型的Cocoa抽象,是一套Objective-C的API,爲了使併發(多線程)編程變得更加簡單,但效率比GCD略低。在實際開發中NSOperationQueue是首選。安全
(2) GCD提供了更加底層的控制,而操做隊列則在GCD之上實現了一些方便的功能,這些功能對於開發者而言一般是最好最安全的選擇。網絡
隊列及操做多線程
(1)NSOperationQueue有兩種不一樣類型的隊列:主隊列和自定義隊列併發
(2)主隊列運行在主線程上。異步
(3)自定義隊列在後臺執行(只要自定義隊列,都是併發的)。atom
(4) NSOperation是不能直接使用的,隊列處理的任務是NSOperation的子類:線程
(a)NSInvocationOperation隊列
(b)NSBlockOperation圖片
2、NSOperation的基本使用步驟
基本使用步驟
(1) 定義操做隊列
(2) 定義操做
(3) 將操做添加到隊列
提示:一旦將操做添加到隊列,操做就會當即被調度執行
3、NSInvocationOperation(調度操做)
定義隊列:
self.myQueue = [[NSOperationQueue alloc] init];
操做調用的方法:
- (void)operationAction:(id)obj
{
NSLog(@"%@ - obj : %@", [NSThread currentThread], obj);
}
定義操做並添加到隊列:
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationAction:) object:@(i)];
[self.myQueue addOperation:op];
例如:
其中myQueue 爲:
@property (nonatomic, strong) NSOperationQueue *myQueue;
- (void)demoOp2
{
// 須要定義一個方法,可以接收一個參數
// 是用起來不夠靈活
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demoOp:) object:@"hello op"];
// [self.myQueue addOperation:op];//在子線程運行
[[NSOperationQueue mainQueue] addOperation:op];//在主線程運行
}
4、NSBlockOperation(塊操做)
定義操做並添加到隊列
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
[self operationAction:@"Block Operation"];
}];
將操做添加到隊列
[self.myQueue addOperation:op];
【備註】NSBlockOperation比NSInvocationOperation更加靈活
例如:
其中myQueue 爲:
@property (nonatomic, strong) NSOperationQueue *myQueue;
#pragma mark 設置任務的執行順序
- (void)demoOp3
{
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(@"更新UI %@", [NSThread currentThread]);
}];
// 設定執行順序, Dependency依賴,系統可能會開多個線程,但不會太多
// 依賴關係是能夠跨隊列的!
[op2 addDependency:op1];
[op3 addDependency:op2];
[op4 addDependency:op3];
// GCD是串行隊列,異步任務,只會開一個線程
[self.myQueue addOperation:op1];
[self.myQueue addOperation:op2];
[self.myQueue addOperation:op3];
// 全部UI的更新須要在主線程上進行,使op4在主線程執行
[[NSOperationQueue mainQueue] addOperation:op4];
}
5、設置操做的依賴關係
NSBlockOperation *op1 =
[NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@ - 下載圖片", [NSThread currentThread]);
}];
NSBlockOperation *op2 =
[NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@ - 添加圖片濾鏡", [NSThread currentThread]);
}];
NSBlockOperation *op3 =
[NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@ - 更新UI", [NSThread currentThread]);
}];
// [op1 addDependency:op3];會形成循環依賴
[op2 addDependency:op1];
[op3 addDependency:op2];
[self.myQueue addOperation:op1];
[self.myQueue addOperation:op2];
[[NSOperationQueue mainQueue] addOperation:op3];
提示:利用addDependency能夠指定操做之間的彼此依賴關係(執行前後順序)
注意:不要出現循環依賴!
6、設置同時併發的線程數量
//設置同時併發的線程數量可以有效地下降CPU和內存的開銷,這一功能用GCD不容易實現。
// 新建線程是有開銷的
// 在設定同時併發的最大線程數時,若是前一個線程工做完成,可是尚未銷燬,會新建線程
// 應用場景:網絡開發中,下載工做!(線程開銷:CPU,MEM)電量!
// 若是是3G,開3個子線程
// 若是是WIFI,開6個子線程
[self.myQueue setMaxConcurrentOperationCount:2];
for (int i = 0; i < 10; ++i) {
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
[self operationAction:@(i)];
}];
[self.myQueue addOperation:op];
}