實(shí)現(xiàn)多線程的具體步驟
- 先將需要執(zhí)行的操作封裝到一個(gè)
NSOperation對(duì)象
中 - 然后將
NSOperation對(duì)象
添加到NSOperationQueue
中 - 系統(tǒng)自動(dòng)從
NSOperationQueue
中取出NSOperation對(duì)象
放到適合的線程中執(zhí)行
NSOperation
- NSOperation是個(gè)
抽象類
,并不具備封裝操作的能力 - 只能通過它的
子類
來使用它的功能 - 有三種方式來使用NSOperation
- NS
Invocation
Operation - NS
Block
Operation -
自定義
繼承自NSOperation的操作
- NS
NSInvocationOperation
- 創(chuàng)建NS
Invocation
Operation對(duì)象馋记,通過對(duì)象方法創(chuàng)建
- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;
-
必須
手動(dòng)調(diào)用start
方法才開始執(zhí)行操作 -
默認(rèn)
情況下,調(diào)用了start
方法后并不會(huì)
開一條新線程去執(zhí)行操作村象,而是在當(dāng)前線程中同步執(zhí)行
操作
- (void)invocationOperation
{
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
// 調(diào)用start方法
[op start];
}
- (void)run
{
NSLog(@"------%@", [NSThread currentThread]);
}
NSBlockOperation
- 創(chuàng)建NS
Block
Operation對(duì)象榨崩,通過類方法創(chuàng)建
+ (id)blockOperationWithBlock:(void (^)(void))block;
- 通過
addExecutionBlock:
方法添加多個(gè)操作
- (void)addExecutionBlock:(void (^)(void))block;
-
必須
手動(dòng)調(diào)用start
方法才開始執(zhí)行操作
- (void)blockOperation
{
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^
{
// 這個(gè)任務(wù)是在【主線程】
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];
}
-
第一個(gè)
任務(wù)是在當(dāng)前線程中執(zhí)行削解,后續(xù)的任務(wù)才會(huì)在子線程中執(zhí)行 -
只有
當(dāng)封裝的操作數(shù)> 1
把夸,才會(huì)異步
執(zhí)行操作
自定義繼承自NSOperation的操作
- 重寫
- (void)main
方法,在里面實(shí)現(xiàn)想執(zhí)行的任務(wù)邏輯 - 自己創(chuàng)建
自動(dòng)釋放池
锋华,如果操作是在子線程中完成嗡官,那么子線程中是無法訪問主線程的自動(dòng)釋放池,所以自定Operation需要在外層添加@autoreleasepool{ }
- 合理布局供置,在適當(dāng)位置調(diào)用
isCancelled
屬性檢測(cè)操作是否已被取消谨湘,及時(shí)中斷操作
- (void)main
{
@autoreleasepool
{
for (NSInteger i = 0; i < 1000; i++)
{
NSLog(@"download1 -%zd-- %@", i, [NSThread currentThread]);
}
// 由于任務(wù)一旦開始執(zhí)行就沒辦法停止下來
// 蘋果官方建議,如果是自定義的Operation芥丧,而且內(nèi)部的執(zhí)行邏輯很耗時(shí)
// 如果外面調(diào)用了cancel方法,可以通過在一段耗時(shí)邏輯后調(diào)用一次isCancelled方法判斷操作是否已經(jīng)取消坊罢,以用來中斷任務(wù)的執(zhí)行
// 合理布局此方法
if (self.isCancelled) return;
for (NSInteger i = 0; i< 1000; i++)
{
NSLog(@"download2 -%zd-- %@", i, [NSThread currentThread]);
}
if (self.isCancelled) return;
for (NSInteger i = 0; i < 1000; i++)
{
NSLog(@"download3 -%zd-- %@", i, [NSThread currentThread]);
}
if (self.isCancelled) return;
}
}
NSOperation設(shè)置依賴
- 比如任務(wù)A執(zhí)行完后续担,才能執(zhí)行任務(wù)B,可以這么設(shè)置
// 操作B依賴于操作A
[operationB addDependency:operationA];
-
可以在不同隊(duì)列的NSOperation之間創(chuàng)建依賴關(guān)系
不同隊(duì)列的NSOperation之間創(chuàng)建依賴關(guān)系 - NSOperation之間
不能相互依賴
活孩,比如:A依賴B物遇,B依賴A
- (void)addDependencyTest
{
// 直接創(chuàng)建
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è)置依賴后再添加到隊(duì)列
// 當(dāng)op1和op2都執(zhí)行完才執(zhí)行op3,但是op1和op2誰先執(zhí)行完不確定
[op3 addDependency:op1];
[op3 addDependency:op2];
// 【不能】循環(huán)依賴
// [op3 addDependency:op1];
// [op1 addDependency:op3];
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
}
- NSOperation
執(zhí)行完畢后
想做一些收尾
的事情憾儒,可以設(shè)置completionBlock
屬性
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^
{
NSLog(@"download----%@", [NSThread currentThread]);
}];
// 任務(wù)執(zhí)行完畢就會(huì)執(zhí)行這個(gè)block
op.completionBlock = ^
{
// 也是在子線程中執(zhí)行
NSLog(@"op執(zhí)行完畢后執(zhí)行---%@", [NSThread currentThread]);
};
NSOperationQueue
- 直接創(chuàng)建
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
- 如果將NSOperation添加到NSOperationQueue中询兴,系統(tǒng)會(huì)
自動(dòng)異步
執(zhí)行NSOperation中的操作 - 本質(zhì)上NSOperationQueue內(nèi)部也是自動(dòng)調(diào)用了NSOperation的
start
方法來執(zhí)行任務(wù) - 同時(shí)包含了
串行 和 并行
功能
添加操作到NSOperationQueue中方法
- (void)addOperation:(NSOperation *)op;
// 推薦使用此種方式添加任務(wù)
- (void)addOperationWithBlock:(void (^)(void))block;
最大并發(fā)數(shù)
- 同時(shí)執(zhí)行的最大任務(wù)數(shù)
- 當(dāng)最大并發(fā)數(shù)為
1
的時(shí)候就是串行隊(duì)列
,但所有任務(wù)不一定
在同一個(gè)
線程上執(zhí)行完起趾,可能在多個(gè)
線程上執(zhí)行诗舰,但一定是按順序
執(zhí)行 - 最大并發(fā)數(shù)設(shè)置方式
// 調(diào)用示例
queue.maxConcurrentOperationCount = 1;
暫停和恢復(fù)隊(duì)列:suspended
- 暫停后
還未執(zhí)行
的任務(wù)將不會(huì)被執(zhí)行,但是已經(jīng)開始
的任務(wù)是不能
立即停下來了
// 調(diào)用示例
queue.suspended = !self.queue.suspended;
- suspended的應(yīng)用場(chǎng)景:隊(duì)列正在執(zhí)行一些耗時(shí)操作训裆,當(dāng)用戶執(zhí)行滾動(dòng)操作時(shí)眶根,為了用戶體驗(yàn)可以調(diào)用這個(gè)屬性先讓隊(duì)列中的任務(wù)暫停執(zhí)行,以用來提高用戶體驗(yàn)
取消隊(duì)列的所有操作:cancelAllOperations
- 取消隊(duì)列中的所有任務(wù)边琉,會(huì)將隊(duì)列中的任務(wù)全部移除
- 這個(gè)方法內(nèi)部其實(shí)是調(diào)用了NSOperation中的
cancel
方法 - 所以可以通過NSOperation中的cancel方法來取消
單個(gè)
操作 -
只能
取消還未執(zhí)行
的任務(wù)属百,已經(jīng)開始
的任務(wù)不能取消
,除非任務(wù)中主動(dòng)判斷了是否取消操作queue.isCancelled
來中斷操作
// 調(diào)用示例
[queue cancelAllOperations];
線程間通信
- (void)test
{
[[[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;
}];
}];
}
GCD的隊(duì)列和NSOperationQueue隊(duì)列對(duì)比
GCD的隊(duì)列
- 并發(fā)隊(duì)列
- 自己創(chuàng)建的(
DISPATCH_QUEUE_CONCURRENT
) - 全局隊(duì)列
- 自己創(chuàng)建的(
- 串行隊(duì)列
- 自己創(chuàng)建的(
DISPATCH_QUEUE_SERIAL or NULL
) - 主隊(duì)列(特殊的串行隊(duì)列)
- 自己創(chuàng)建的(
NSOperationQueue隊(duì)列類型
- 主隊(duì)列
- [NSOperationQueue mainQueue]
- 凡是添加到主隊(duì)列中的任務(wù)(NSOperation)变姨,都會(huì)放到
主線程
中執(zhí)行
- 非主隊(duì)列(其他隊(duì)列)
- 創(chuàng)建:[[NSOperationQueue alloc] init]
- 同時(shí)包含了
串行 和 并行
功能 - 當(dāng)設(shè)置最大并發(fā)數(shù)為
queue.maxConcurrentOperationCount = 1
時(shí)就是串行隊(duì)列
- 添加到隊(duì)列中的操作族扰,會(huì)
自動(dòng)
放到適合的線程中執(zhí)行