NSOperation
- 一個(gè)NSOperation就是一個(gè)操作坏为,可以擁有至少一個(gè)任務(wù)究驴,它可以調(diào)用start方法執(zhí)行任務(wù),默認(rèn)是同步執(zhí)行久脯,即在主線程執(zhí)行
- 作用:配合使用NSOperation和NSOperationQueue纳胧,可以實(shí)現(xiàn)多線程編程(即可異步執(zhí)行任務(wù))
-
NSOperation子類
- NSOperation是一個(gè)抽象類,不具備封裝任務(wù)(操作)的能力帘撰,必須使用它的子類進(jìn)行封裝
- 使用NSOperation子類的方式有3種:
- NSInvocationOperation (少用)
// 如果不添加到隊(duì)列中跑慕,則在主線程上運(yùn)行操作 NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nilo]; [op start];
- NSBlockOperation,如果不添加到隊(duì)列中摧找,第一個(gè)block在主線程運(yùn)行核行,添加的額外block在子線程上執(zhí)行
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"任務(wù)1--%@", [NSTread currentTread]) // 主線程 }]; [op addExecutionBlock:^{ NSLog(@"任務(wù)2--%@", [NSTread currentTread]) // 子線程 }]; [op addExecutionBlock:^{ NSLog(@"任務(wù)3--%@", [NSTread currentTread]) // 子線程 }]; [op addExecutionBlock:^{ NSLog(@"任務(wù)4--%@", [NSTread currentTread]) // 子線程 }];
- 自定義子類繼承NSOperation,實(shí)現(xiàn)內(nèi)部相應(yīng)的方法
// main方法是入口蹬耘,必須將任務(wù)放到main方法中才會(huì)執(zhí)行 - (void)main {...};
NSOperationQueue
NSOperationQueue是基于GCD的面向?qū)ο蟮年?duì)列
- NSOperationQueue隊(duì)列類型
- 主隊(duì)列:任務(wù)在主線程執(zhí)行
[NSOperationQueue mainQueue];
- 其他隊(duì)列(串行芝雪、并發(fā)):任務(wù)在子線程執(zhí)行
// 默認(rèn)并發(fā) NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 實(shí)現(xiàn)串行,可設(shè)置 maxConcurrentOperationCount 屬性 = 1,其默認(rèn)值是 -1 queue.maxConcurrentOperationCount = 1;
- GCD的隊(duì)列類型
- 并發(fā)隊(duì)列:
- 自己創(chuàng)建的
- 全局的
- 串行隊(duì)列:
- 主隊(duì)列
- 自己創(chuàng)建的
-
實(shí)現(xiàn)多線程的步驟
-
方式一:
- 創(chuàng)建隊(duì)列:NSOperationQueue
- 創(chuàng)建操作:NSOperation
- 將NSOperation對(duì)象添加到NSOperationQueue中(系統(tǒng)會(huì)自動(dòng)將NSOperationQueue中的NSOperation取出來综苔,并自動(dòng)放到一條線程中執(zhí)行任務(wù))
- 主線程里執(zhí)行:放到主隊(duì)列
- 子線程里執(zhí)行:放到其他隊(duì)列(即創(chuàng)建的隊(duì)列)
-
方式二:
- 創(chuàng)建隊(duì)列:NSOperationQueue
- 直接將任務(wù)添加到隊(duì)列中惩系。
具體實(shí)現(xiàn)
/** 方式一 **/ // 1. 創(chuàng)建隊(duì)列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 2. 創(chuàng)建操作(任務(wù)) // 操作1任務(wù)1 NSInvocationOperation NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download1) object:nil]; // 操作2任務(wù)2 NSBlockOperation NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{...}]; // 操作2任務(wù)3 NSBlockOperation [op2 addExecutionBlock:^{...}]; // 操作3任務(wù)4 使用自定義JKYOperation,該類中需要實(shí)現(xiàn)-(void)main方法,并將任務(wù)添加其中如筛,才會(huì)執(zhí)行的任務(wù) JKYOperation *op3 = [[JKYOperation alloc] init]; // 3. 添加任務(wù)到隊(duì)列中 [queue addOperation:op1]; [queue addOperation:op2]; [queue addOperation:op3]; /** 方式二 **/ // 1. 創(chuàng)建隊(duì)列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 2. 添加任務(wù) [queue addOperationWithBlock:^{...}];
-
-
隊(duì)列的掛起與取消
隊(duì)列執(zhí)行掛起或取消的同時(shí)堡牡,operation的任務(wù)還在執(zhí)行,則會(huì)執(zhí)行完當(dāng)前任務(wù)杨刨,再停止晤柄。
- 蘋果推薦的解決方案:
自定義NSOperation,并在類中相對(duì)耗時(shí)的任務(wù)后判讀當(dāng)前隊(duì)列是否處于暫脱停或取消狀態(tài)芥颈,如果是則return;
-(void)main { //耗時(shí)任務(wù)執(zhí)行后,判斷 if(self.isCanceled || self.isSusended) return; }
-
操作依賴和監(jiān)聽
在多線程中赚抡,并發(fā)執(zhí)行多個(gè)操作爬坑,無法控制其調(diào)用順序,可添加依賴實(shí)現(xiàn)順序調(diào)用
具體實(shí)現(xiàn)
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{...}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{...}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{...}];
/** 監(jiān)聽 **/
op3.completionBlock = ^{NSLog(@"op3執(zhí)行完畢");};
/** 依賴 **/
// op3依賴op1,op3依賴op2
// 可跨隊(duì)列添加依賴
[op3 addDependency:op1];
[op3 addDependency:op2];
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
//
// 注意:
// 1. 應(yīng)在加入隊(duì)列之前添加依賴
// 2. 不可兩個(gè)操作相互添加依賴
-
線程之間通信
具體實(shí)現(xiàn)
[[NSOperationQueue alloc] init] addOperationWithBlock:^{
// 圖片的網(wǎng)絡(luò)路徑
NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/123234.jpg"];
// 加載圖片
NSData *data = [NSDdata dataWithContentsOfURL:url];
// 生成圖片
UIImage *image = [UIImage imageWithData:data];
// 回到主線程
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.imageView.image = image;
}]