NSOperation實現(xiàn)多線程編程,實現(xiàn)步驟大致是這樣的:
- 先將需要執(zhí)行的操作封裝到一個NSOperation對象中
- 然后將NSOperation對象添加到NSOperationQueue中
- 系統(tǒng)會自動將NSOperation中封裝的操作放到一條新線程中執(zhí)行
但是NSOperation本身是一個抽象類,要使用可以通過以下幾個辦法:
- 使用NSInvocationOperation
- 使用NSBlockOperation
- 自定義NSOperation的子類
簡單的使用方法
NSInvocationOperation簡單用法:
//創(chuàng)建操作
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector: @selector(download) object:nil];
//執(zhí)行封裝好的操作
[operation start];
-(void)download
{
NSLog(@"download----線程號:%@", [NSThreadcurrentThread]);
}
NSBlockOperation簡單用法:
NSBlockOperation*operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"這里是線程操作1線程號:%@", [NSThread currentThread]);
}];
[operation1 start];
根據(jù)打印的結(jié)果我們會發(fā)現(xiàn),直接調(diào)用start方法時,系統(tǒng)并不會開辟一個新的線程去執(zhí)行任務(wù),任務(wù)會在當(dāng)前線程同步執(zhí)行.
注意: 這里我們說的是當(dāng)前線程而非主線程,意即:如果是在主線程中調(diào)用operation的start方法,那么該任務(wù)是在主線程中執(zhí)行;但如果是在其他子線程調(diào)用start方法,任務(wù)則是在其他子線程執(zhí)行.顯然調(diào)用start方法執(zhí)行操作不是我們開線程的初衷。
NSOperationQueue使用
NSOperation與NSOperationQueue進(jìn)行結(jié)合,才會發(fā)揮出這種多線程技術(shù)的最大功效.當(dāng)NSOperation被添加到NSOperationQueue中后,就會全自動地執(zhí)行異步操作.
//創(chuàng)建隊列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//創(chuàng)建操作
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil];
//將操作加入隊列
[queue addOperation: operation];
- (void)download
{
NSLog(@"download----線程號:%@", [NSThread currentThread]);
}
將操作放入隊列中,會自動異步執(zhí)行。
打印信息如下:
download----****線程號:****{number = 2, name = (null)}
我們創(chuàng)建線程就是為了異步執(zhí)行代碼,所以經(jīng)常使用的就是將操作加入隊列中
使用block 創(chuàng)建
//創(chuàng)建隊列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//創(chuàng)建操作
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"這里是線程操作線程號:%@", [NSThread currentThread]);
}];
//將操作加入隊列
[queue addOperation: operation];
打印信息如下:
**這里是線程操作******線程號:****{number = 2, name = (null)}****
從線程號可以看出該線程操作不是在當(dāng)前線程中運行的
創(chuàng)建多個操作來加入隊列
//創(chuàng)建隊列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//創(chuàng)建操作
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"這里是線程操作1線程號:%@", [NSThread currentThread]);
}];
NSBlockOperation*operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"這里是線程操作2線程號:%@", [NSThread currentThread]);
}];
NSBlockOperation*operation3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"這里是線程操作3線程號:%@", [NSThread currentThread]);
}];
//將操作加入隊列
[queue addOperation: operation1];
[queue addOperation: operation2];
[queue addOperation: operation3];
打印信息如下:
2016-02-17 17:34:03.282 tttt[2559:204434]****這里是線程操作****3****線程號:****{number = 4, name = (null)}
2016-02-17 17:34:03.282 tttt[2559:204432]****這里是線程操作****1****線程號:****{number = 3, name = (null)}
2016-02-17 17:34:03.282 tttt[2559:204433]****這里是線程操作****2****線程號:****{number = 2, name = (null)}
從線程號可以看出該線程操作不是在當(dāng)前線程中運行的
在一個操作中添加多個子任務(wù)
//創(chuàng)建隊列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//創(chuàng)建操作
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"這里是線程操作1線程號:%@", [NSThread currentThread]);
}];
[operation1 addExecutionBlock:^{
NSLog(@"這里是線程操作1的分支線程號:%@", [NSThread currentThread]);
}];
//將操作加入隊列
[queue addOperation: operation1];
打印信息如下:
2016-02-17 17:37:28.037 tttt[2572:207727]****這里是線程操作****1****線程號:****{number = 2, name = (null)}
**2016-02-17 17:37:28.037 tttt[2572:207728]****這里是線程操作****1****的分支******線程號:****{number = 3, name = (null)}****
可以看到,自動分成了兩個線程來操作,且第二個線程一定是在第一個線程執(zhí)行完畢才開始執(zhí)行
----------------
但是這種增加任務(wù)的方法和上面那種還是有區(qū)別
代碼如下:
//創(chuàng)建隊列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//創(chuàng)建操作
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"這里是線程操作1線程號:%@", [NSThread currentThread]);
}];
[operation1 addExecutionBlock:^{
NSLog(@"這里是線程操作1的分支線程號:%@", [NSThread currentThread]);
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"這里是線程操作2線程號:%@", [NSThread currentThread]);
}];
//將操作加入隊列
[queue addOperation: operation1];
[queue addOperation: operation2];
創(chuàng)建兩個操作來加入隊列中,其中線程操作1有一個分支任務(wù)
打印結(jié)果如下:
2016-02-17 17:41:35.210 tttt[2587:211052]****這里是線程操作****2****線程號:****{number = 2, name = (null)}
2016-02-17 17:41:35.210 tttt[2587:211051]****這里是線程操作****1****線程號:****{number = 3, name = (null)}
**2016-02-17 17:41:35.210 tttt[2587:211055]****這里是線程操作****1****的分支******線程號:****{number = 4, name = (null)}****
可以看到,線程操作1和線程操作2先執(zhí)行,操作1的分支任務(wù)最后執(zhí)行。有一個明顯的先后關(guān)系。
使用隊列添加線程操作
//創(chuàng)建隊列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//創(chuàng)建操作
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"這里是線程操作1線程號:%@", [NSThread currentThread]);
}];
[operation1 addExecutionBlock:^{
NSLog(@"這里是線程操作1的分支線程號:%@", [NSThread currentThread]);
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"這里是線程操作2線程號:%@", [NSThread currentThread]);
}];
//將操作加入隊列
[queue addOperation: operation1];
[queue addOperation: operation2];
[queue addOperationWithBlock:^{
NSLog(@"這里是線程操作3線程號:%@", [NSThread currentThread]);
}];
直接使用隊列對象來添加線程操作。
打印信息如下:
2016-02-17 18:01:25.354 tttt[2615:221510]****這里是線程操作****3****線程號:****{number = 3, name = (null)}
2016-02-17 18:01:25.354 tttt[2615:221506]****這里是線程操作****2****線程號:****{number = 2, name = (null)}
2016-02-17 18:01:25.354 tttt[2615:221504]****這里是線程操作****1****線程號:****{number = 4, name = (null)}
**2016-02-17 18:01:25.354 tttt[2615:221514]****這里是線程操作****1****的分支******線程號:****{number = 5, name = (null)}****
線程3是通過隊列queue直接加入進(jìn)來的,但其效果和使用operation是一樣的
設(shè)置最大線程并發(fā)數(shù)
可以通過maxConcurrentOperationCount來設(shè)置最大線程并發(fā)數(shù)
//創(chuàng)建隊列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//設(shè)置最大并發(fā)數(shù)
queue.maxConcurrentOperationCount=2;
//創(chuàng)建操作
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"這里是線程操作1線程號:%@", [NSThread currentThread]);
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"這里是線程操作2線程號:%@", [NSThread currentThread]);
}];
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"這里是線程操作3線程號:%@", [NSThread currentThread]);
}];
NSBlockOperation *operation4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"這里是線程操作4線程號:%@", [NSThread currentThread]);
}];
//將操作加入隊列
[queue addOperation: operation1];
[queue addOperation: operation2];
[queue addOperation: operation3];
[queue addOperation: operation4];
打印信息如下:
2016-02-23 15:20:32.315 tttt[1443:161764] ****這里是線程操作****2 ****線程號:****<NSThread: 0x7fd019d30730>{number = 3, name = (null)}
2016-02-23 15:20:32.315 tttt[1443:161765] ****這里是線程操作****1 ****線程號:****<NSThread: 0x7fd019f0a290>{number = 2, name = (null)}
2016-02-23 15:20:32.316 tttt[1443:161766] ****這里是線程操作****3 ****線程號:****<NSThread: 0x7fd019ea8890>{number = 5, name = (null)}
2016-02-23 15:20:32.316 tttt[1443:161767] ****這里是線程操作****4 ****線程號:****<NSThread: 0x7fd019d00e10>{number = 4, name = (null)}
根據(jù)線程開啟時間可以看出,同一時間只有兩個線程開啟
本篇先講到這里,下一篇說一說自定義NSOperation的子類