一、NSOperation簡介
NSOperation 是對 GCD 的封裝,完全面向對象。 NSOperation 和 NSOperationQueue分別對應 GCD 的任務和隊列。
1.簡單說明
NSOperation的作?:配合使用NSOperation和NSOperationQueue也能實現多線程編程。
NSOperation和NSOperationQueue實現多線程的具體步驟:
(1)先將需要執行的操作封裝到一個NSOperation對象中。
(2)然后將NSOperation對象添加到NSOperationQueue中。
(3)系統會?動將NSOperationQueue中的NSOperation取出來。
(4)將取出的NSOperation封裝的操作放到?條新線程中執?。
2.NSOperation的子類
NSOperation是個抽象類,并不具備封裝操作的能力,必須使?它的子類。
使用NSOperation?類的方式有3種:
(1)NSInvocationOperation
(2)NSBlockOperation
(3)自定義子類繼承NSOperation,實現內部相應的?法
二、 使用方法
1.NSInvocationOperation類
- (void)viewDidLoad
{
[super viewDidLoad];
//NSOperation:抽象類,不具備封裝功能
//創建操作對象,封裝要執行的任務
//NSInvocationOperation 封裝操作
NSInvocationOperation *operation=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test) object:nil];
//執行操作
[operation start];
}
-(void)test
{
NSLog(@"NSThread---%@",[NSThread currentThread]);
}
總結:操作對象默認在主線程中執行,只有添加到隊列中才會開啟新的線程。即默認情況下,如果操作沒有放到隊列中queue中,都是同步執行。只有將NSOperation放到一個NSOperationQueue中,才會異步執行操作
2.NSBlockOperation類
例1:
- (void)viewDidLoad
{
[super viewDidLoad];
//創建NSBlockOperation操作對象
NSBlockOperation *operation=[NSBlockOperation blockOperationWithBlock:^{
NSLog(@"NSBlockOperation------%@",[NSThread currentThread]);
}];
//開啟執行操作
[operation start];
}
例2:
- (void)viewDidLoad
{
[super viewDidLoad];
//創建NSBlockOperation操作對象
NSBlockOperation *operation=[NSBlockOperation blockOperationWithBlock:^{
NSLog(@"NSBlockOperation------%@",[NSThread currentThread]);
}];
//添加操作
[operation addExecutionBlock:^{
NSLog(@"NSBlockOperation1------%@",[NSThread currentThread]);
}];
[operation addExecutionBlock:^{
NSLog(@"NSBlockOperation2------%@",[NSThread currentThread]);
}];
//開啟執行操作
[operation start];
}
總結:只要NSBlockOperation封裝的操作數 > 1,就會異步執行操作
3.NSOperationQueue
NSOperationQueue的作?:NSOperation可以調?start?法來執?任務,但默認是同步執行的
如果將NSOperation添加到NSOperationQueue(操作隊列)中,系統會自動異步執行NSOperation中的操作
添加操作到NSOperationQueue中,自動執行操作,自動開啟線程
- (void)viewDidLoad
{
[super viewDidLoad];
//創建NSInvocationOperation對象,封裝操作
NSInvocationOperation *operation1=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test1) object:nil];
NSInvocationOperation *operation2=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test2) object:nil];
//創建對象,封裝操作
NSBlockOperation *operation3=[NSBlockOperation blockOperationWithBlock:^{
NSLog(@"NSBlockOperation3--1----%@",[NSThread currentThread]);
}];
[operation3 addExecutionBlock:^{
NSLog(@"NSBlockOperation3--2----%@",[NSThread currentThread]);
}];
//創建NSOperationQueue
NSOperationQueue * queue=[[NSOperationQueue alloc]init];
//把操作添加到隊列中
[queue addOperation:operation1];
[queue addOperation:operation2];
[queue addOperation:operation3];
}
-(void)test1
{
NSLog(@"NSInvocationOperation--test1--%@",[NSThread currentThread]);
}
-(void)test2
{
NSLog(@"NSInvocationOperation--test2--%@",[NSThread currentThread]);
}
總結:這里一共有四個任務,operation1和operation2分別有一個任務,operation3有兩個任務。一共四個任務,開啟了四條線程。通過任務執行的時間全部都是一樣的可以看出,這些任務是并行執行的。
提示:隊列的取出是有順序的,與打印結果并不矛盾。這就好比,選手A,BC雖然起跑的順序是先A,后B,然后C,但是到達終點的順序卻不一定是A,B在前,C在后。
4.其他
NSOperation有一個非常實用的功能,那就是添加依賴。比如有 3 個任務:A: 從服務器上下載一張圖片,B:給這張圖片加個水印,C:把圖片返回給服務器。這時就可以用到依賴了:
- (void)viewDidLoad
{
[super viewDidLoad];
//1.任務一:下載圖片
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"下載圖片 - %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:5.0];
}];
//2.任務二:打水印
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"打水印 - %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:5.0];
}];
//3.任務三:上傳圖片
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"上傳圖片 - %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:5.0];
}];
//4.設置依賴
[operation2 addDependency:operation1]; //任務二依賴任務一
[operation3 addDependency:operation2]; //任務三依賴任務二
//5.創建隊列并加入任務
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperations:@[operation3, operation2, operation1] waitUntilFinished:NO];
}
注意:不能添加相互依賴,會死鎖,比如 A依賴B,B依賴A。
可以使用removeDependency來解除依賴關系。
可以在不同的隊列之間依賴,反正就是這個依賴是添加到任務身上的,和隊列沒關系。