一、
NSOperation是基于GCD之上的更高一層封裝,NSOperation需要配合NSOperationQueue來(lái)實(shí)現(xiàn)多線程。
NSOperation實(shí)現(xiàn)多線程的步驟如下:
1、創(chuàng)建任務(wù):先將需要執(zhí)行的操作封裝到NSOperation對(duì)象中。
2、創(chuàng)建隊(duì)列:創(chuàng)建NSOperationQueue。
3、將任務(wù)加入到隊(duì)列中:將NSOperation對(duì)象添加到NSOperationQueue中。
需要注意的是,NSOperation是個(gè)抽象類(lèi),實(shí)際運(yùn)用中需要使用它的子類(lèi),有三種方式:
1、使用子類(lèi)NSInvocationOperation
2、使用子類(lèi)NSBlockOperation
3、定義繼承NSOreration的子類(lèi),通過(guò)實(shí)現(xiàn)內(nèi)部相應(yīng)的方法來(lái)封裝任務(wù)。
NSOperation的三種創(chuàng)建方式
1、NSInvocationOperation的使用
創(chuàng)建NSInvocationOperation對(duì)象并關(guān)聯(lián)方法,之后start。
-(void)testNSInvocationOperation {
//創(chuàng)建NSInvocationOperaion
NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOperation) object:nil];
[invocationOperation start];
}
-(void)invocationOperation {
NSLog(@"NSInvocationOperation包含的任務(wù),沒(méi)有加入隊(duì)列=======%@",[NSThread currentThread]);
}
結(jié)論:程序在主線程執(zhí)行,沒(méi)有開(kāi)啟新線程。
這是因?yàn)镹SOperation多線程的使用需要配合隊(duì)列NSOperationQueue來(lái)實(shí)現(xiàn)多線程
二、NSBlockOperation的使用
把任務(wù)放到NSBlockOperation的block中,然后start。
-(void)testNSBlockOperation {
//把任務(wù)放到block中
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"NSBlockOperation包含的任務(wù),沒(méi)有加入隊(duì)列=====%@",[NSThread currentThread]);
}];
[blockOperation start];
}
得出結(jié)論:主線程執(zhí)行,沒(méi)有開(kāi)啟新線程。
同樣的,NSBlockOperation可以配合隊(duì)列NSOperationQueue來(lái)實(shí)現(xiàn)多線程。
但是NSBlockOperation有一個(gè)方法addExecutionBlock:,通過(guò)這個(gè)方法可以讓NSBlockOperation實(shí)現(xiàn)多線程。
-(void)testNSBLockOperationExecution {
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBLock:^{
NSLog(@"NSBlockOperation運(yùn)用addExecutionBlock主任務(wù)========%@", [NSThread currentThread]);
}];
[blockOperation addExecutionBlock:^{
NSLog(@"NSBlockOperation運(yùn)用addExecutionBlock方法添加任務(wù)1========%@", [NSThread currentThread]);
}];
[blockOperation addExecutionBlock:^{
NSLog(@"NSBlockOperation運(yùn)用addExecutionBlock方法添加任務(wù)2========%@", [NSThread currentThread]);
}];
[blockOperation addExecutionBlock:^{
NSLog(@"NSBlockOperation運(yùn)用addExecutionBlock方法添加任務(wù)3========%@", [NSThread currentThread]);
}];
[blockOperation start];
}
可以看出,NSBlockOperation創(chuàng)建時(shí)block中的任務(wù)是在主線程執(zhí)行,而運(yùn)用addExecutionBlock加入的任務(wù)是在子線程執(zhí)行的。
3、運(yùn)用繼承自NSOperation的子類(lèi)(略過(guò))
三、隊(duì)列NSOperationQueue
NSOperationQueue只有兩種隊(duì)列:主隊(duì)列、其他隊(duì)列。其他隊(duì)列包含了串行和并發(fā)。
主隊(duì)列的創(chuàng)建如下,主隊(duì)列上的任務(wù)是在主線程執(zhí)行的。
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
注意:
1、非主隊(duì)列(其他隊(duì)列)可以實(shí)現(xiàn)串行或并行。
2、隊(duì)列NSOperationQueue有一個(gè)參數(shù)中做最大并發(fā)數(shù):maxConcurrentOperationCount。
3、maxConcurrentOperatoinCount默認(rèn)為-1,直接并發(fā)執(zhí)行,所以加入到'非隊(duì)列'中的任務(wù)默認(rèn)就是并發(fā),開(kāi)啟多線程。
4、當(dāng)maxConcurrentOperationCount為1時(shí),則表示不開(kāi)線程,也就是串行。
5、當(dāng)maxConcurrentOperationCount大于1時(shí),進(jìn)行并發(fā)執(zhí)行。
6、系統(tǒng)對(duì)最大并發(fā)數(shù)有一個(gè)限制,所以即使程序員把maxconcurrentOperationiCount設(shè)置的很大,系統(tǒng)也會(huì)自動(dòng)調(diào)整。所以把最大并發(fā)數(shù)設(shè)置的很大是沒(méi)有意義的。
四、NSOperation+NSOperationQueue
把任務(wù)加入隊(duì)列,這才是NSOperation的常規(guī)使用方式。
1、addOperation添加任務(wù)到隊(duì)列
先創(chuàng)建好任務(wù),然后運(yùn)用-(void)addOperation:(NSOpreation*)op方法來(lái)把任務(wù)添加到隊(duì)列中,示例代碼如下:
- (void)testOperationQueue {
// 創(chuàng)建隊(duì)列,默認(rèn)并發(fā)
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 創(chuàng)建操作,NSInvocationOperation
NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOperationAddOperation) object:nil];
// 創(chuàng)建操作,NSBlockOperation
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
for (int i = 0; i < 3; i++) {
NSLog(@"addOperation把任務(wù)添加到隊(duì)列======%@", [NSThread currentThread]);
}
}];
[queue addOperation:invocationOperation];
[queue addOperation:blockOperation];
}
- (void)invocationOperationAddOperation {
NSLog(@"invocationOperation===aaddOperation把任務(wù)添加到隊(duì)列====%@", [NSThread currentThread]);
}
2、addOperationWithBlock添加任務(wù)到隊(duì)列
這是一個(gè)更方便的把任務(wù)添加到隊(duì)列的方法,直接把任務(wù)寫(xiě)在block中,添加到任務(wù)中。
- (void)testAddOperationWithBlock {
// 創(chuàng)建隊(duì)列,默認(rèn)并發(fā)
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 添加操作到隊(duì)列
[queue addOperationWithBlock:^{
for (int i = 0; i < 3; i++) {
NSLog(@"addOperationWithBlock把任務(wù)添加到隊(duì)列======%@", [NSThread currentThread]);
}
}];
}
五、NSOperation的其他操作
1、取消隊(duì)列NSOperationQueue的所有操作,NSOperationQueue對(duì)象方法----cancelAllOperations
2、取消NSOperation的某個(gè)操作,NSOperation對(duì)象方法------cancel
3、使隊(duì)列暫停或繼續(xù)------[queue setSuspended:YES];
4、判斷隊(duì)列是否暫停------isSuspended
六、NSOperation的操作依賴(lài)
NSOperation有一個(gè)非常好用的方法,就是操作依賴(lài)??梢詮淖置嬉馑祭斫猓耗骋粋€(gè)操作(operation2)依賴(lài)于另一個(gè)操作(operation1),只有當(dāng)operation1執(zhí)行完畢,才能執(zhí)行operation2,這時(shí),就是操作依賴(lài)大顯身手的時(shí)候了。
- (void)testAddDependency {
// 并發(fā)隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 操作1
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
for (int i = 0; i < 3; i++) {
NSLog(@"operation1======%@", [NSThread currentThread]);
}
}];
// 操作2
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"****operation2依賴(lài)于operation1,只有當(dāng)operation1執(zhí)行完畢,operation2才會(huì)執(zhí)行****");
for (int i = 0; i < 3; i++) {
NSLog(@"operation2======%@", [NSThread currentThread]);
}
}];
// 使操作2依賴(lài)于操作1
[operation2 addDependency:operation1];
// 把操作加入隊(duì)列
[queue addOperation:operation1];
[queue addOperation:operation2];
}