NSOperation的作用
配合使用NSOperation和NSOperationQueue也能實(shí)現(xiàn)多線程編程
NSOperation和NSOperationQueue實(shí)現(xiàn)多線程的具體步驟
- 先將需要執(zhí)行的操作封裝到一個(gè)NSOperation對(duì)象中
- 然后將NSOperation對(duì)象添加到NSOperationQueue中
- 系統(tǒng)會(huì)自動(dòng)將NSOperationQueue中的NSOperation取出來
- 將取出的NSOperation封裝的操作放到一條新線程中執(zhí)行
注意:
- NSOperation是個(gè)抽象類,并不具備封裝操作的能力河咽,必須使用它的子類
- 使用NSOperation子類的方式有3種:
- NSInvocationOperation
- NSBlockOperation
- 自定義子類繼承NSOperation牵啦,實(shí)現(xiàn)內(nèi)部相應(yīng)的方法
NSInvocationOperation類
- 創(chuàng)建NSInvocationOperation對(duì)象
-(id)initWithTarget:(id)targetselector:(SEL)selobject:(id)arg;
- 調(diào)用start方法開始執(zhí)行操作
-(void)start;
一旦執(zhí)行操作挺举,就會(huì)調(diào)用target的sel方法
- 代碼:
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
[op start];
- (void)run
{
NSLog(@"------%@", [NSThread currentThread]);
}
- 注意:
- 默認(rèn)情況下汹粤,調(diào)用了start方法后并不會(huì)開一條新線程去執(zhí)行操作箩做,而是在當(dāng)前線程同步執(zhí)行操作
- 只有將NSOperation放到一個(gè)NSOperationQueue中虫腋,才會(huì)異步執(zhí)行操作
- 此類僅當(dāng)了解骄酗,在開發(fā)中并不常用
NSBlockOperation類
- 創(chuàng)建NSBlockOperation對(duì)象
+(id)blockOperationWithBlock:(void(^)(void))block;
- 通過addExecutionBlock:方法添加更多的操作
-(void)addExecutionBlock:(void(^)(void))block;
- 代碼:
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
// 在主線程
NSLog(@"下載1------%@", [NSThread currentThread]);
}];
// 添加額外的任務(wù)(在子線程執(zhí)行)
[op addExecutionBlock:^{
NSLog(@"下載2------%@", [NSThread currentThread]);
}];
[op addExecutionBlock:^{
NSLog(@"下載3------%@", [NSThread currentThread]);
}];
[op addExecutionBlock:^{
NSLog(@"下載4------%@", [NSThread currentThread]);
}];
[op start];
- 注意:只要NSBlockOperation封裝的操作數(shù) >1,就會(huì)異步執(zhí)行操作
NSOperationQueue
NSOperationQueue的作用
NSOperation可以調(diào)用start方法來執(zhí)行任務(wù)悦冀,但默認(rèn)是同步執(zhí)行的
如果將NSOperation添加到NSOperationQueue(操作隊(duì)列)中趋翻,系統(tǒng)會(huì)自動(dòng)異步執(zhí)行NSOperation中的操作
添加操作到NSOperationQueue中
-(void)addOperation:(NSOperation*)op;
-(void)addOperationWithBlock:(void(^)(void))block;
- 代碼:
- 方法一:
// 創(chuàng)建隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 創(chuàng)建操作
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download1 --- %@", [NSThread currentThread]);
}];
//添加操作到隊(duì)列中
[queue addOperation:op1];
- 方法二:
// 創(chuàng)建隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//添加操作到隊(duì)列中
[queue addOperationWithBlock:^{
NSLog(@"download1 --- %@", [NSThread currentThread]);
}];
NSOperationQueue的隊(duì)列類型與GCD的隊(duì)列類型對(duì)比
- GCD的隊(duì)列
- 并發(fā)隊(duì)列
- 自己創(chuàng)建的
- 全局
- 串行隊(duì)列
- 主隊(duì)列
- 自己創(chuàng)建的
- NSOperationQueue的隊(duì)列
- 主隊(duì)列
[NSOperationQueue mainQueue]
- 凡是添加到主隊(duì)列中的任務(wù)(NSOperation),都會(huì)放到主線程中執(zhí)行
- 非主隊(duì)列(其他隊(duì)列)
[[NSOperationQueue alloc] init]
- 同時(shí)包含了:串行盒蟆、并發(fā)功能
- 添加到這種隊(duì)列中的任務(wù)(NSOperation)踏烙,就會(huì)自動(dòng)放到子線程中執(zhí)行
最大并發(fā)數(shù)
什么是并發(fā)數(shù)
同時(shí)執(zhí)行的任務(wù)數(shù)
比如,同時(shí)開3個(gè)線程執(zhí)行3個(gè)任務(wù)历等,并發(fā)數(shù)就是3
最大并發(fā)數(shù)的相關(guān)方法
-(NSInteger)maxConcurrentOperationCount;
-(void)setMaxConcurrentOperationCount:(NSInteger)cnt;
- 代碼
// 創(chuàng)建隊(duì)列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 設(shè)置最大并發(fā)操作數(shù) // queue.maxConcurrentOperationCount = 2;// 并發(fā)隊(duì)列 queue.maxConcurrentOperationCount = 1; // 就變成了串行隊(duì)列 // 添加操作 [queue addOperationWithBlock:^{ NSLog(@"download1 --- %@", [NSThread currentThread]) }]; [queue addOperationWithBlock:^{ NSLog(@"download2 --- %@", [NSThread currentThread]) }]; [queue addOperationWithBlock:^{ NSLog(@"download3 --- %@", [NSThread currentThread]) }];
隊(duì)列的取消讨惩、暫停、恢復(fù)
- 取消隊(duì)列的所有操作
-(void)cancelAllOperations;
提示:也可以調(diào)用NSOperation的-(void)cancel方法取消單個(gè)操作
- 暫停和恢復(fù)隊(duì)列
-(void)setSuspended:(BOOL)b;// YES代表暫停隊(duì)列寒屯,NO代表恢復(fù)隊(duì)列
- (BOOL)isSuspended
- 代碼
// 恢復(fù)隊(duì)列荐捻,繼續(xù)執(zhí)行
// self.queue.suspended = NO;
// 暫停(掛起)隊(duì)列,暫停執(zhí)行
// self.queue.suspended = YES;
// 取消隊(duì)列的所有操作
[self.queue cancelAllOperations];
操作依賴
- NSOperation之間可以設(shè)置依賴來保證執(zhí)行順序
- 比如一定要讓操作A執(zhí)行完后寡夹,才能執(zhí)行操作B处面,可以這么寫
[operationB addDependency:operationA];// 操作B依賴于操作A
- 也可以在不同queue的NSOperation之間創(chuàng)建依賴關(guān)系
- 代碼
// 創(chuàng)建隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 添加操作
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download1----%@", [NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download2----%@", [NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download3----%@", [NSThread currentThread]);
}];
// 設(shè)置依賴(保證op3在op1和op2都執(zhí)行完之后再執(zhí)行)
[op3 addDependency:op1];
[op3 addDependency:op2];
- 注意:不能相互依賴
- 比如A依賴B,B依賴A
線程之間的通信
- 舉例:在子線程下載圖片菩掏,再回答到主線程在imageView添加圖片
- 看代碼:
[[[NSOperationQueue alloc] init] addOperationWithBlock:^{
// 圖片的網(wǎng)絡(luò)路徑
NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];
// 加載圖片
NSData *data = [NSData dataWithContentsOfURL:url];
// 生成圖片
UIImage *image = [UIImage imageWithData:data];
// 回到主線程
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.imageView.image = image;
}];
}];
操作的監(jiān)聽
- 可以監(jiān)聽一個(gè)操作的執(zhí)行完畢
-(void(^)(void))completionBlock;
-(void)setCompletionBlock:(void(^)(void))block;
自定義NSOperation
- 自定義NSOperation的步驟很簡(jiǎn)單
- 重寫-(void)main方法魂角,在里面實(shí)現(xiàn)想執(zhí)行的任務(wù)
- 重寫-(void)main方法的注意點(diǎn)
- 自己創(chuàng)建自動(dòng)釋放池(因?yàn)槿绻钱惒讲僮鳎瑹o(wú)法訪問主線程的自動(dòng)釋放池)
- 經(jīng)常通過-(BOOL)isCancelled方法檢測(cè)操作是否被取消智绸,對(duì)取消做出響應(yīng)