iOS自学之NSOperation、NSOperationQueue、Background

  iOS中多线程编程主要分为NSThread、NSOperation和GCD,今天主要记录下自己在学习NSOperation中的点滴~如有不对的地方帮忙指出下,PS:人生第一次写blog,各位看官请轻虐,谢啦~

  NSOperation是abstract类,不能直接使用,可以使用CocoTouch提供的NSBlockOperaion和NSInvocationOperation,也可以自己实现subclass。NSOperation可以理解为一个独立的任务,没有调度功能,真正利用NSOperation实现多线程的关键是NSOperationQueue,当NSOperation 添加到NSOperationQueue后,NSOperationQueue就会给队列中的NSOperation分配线程并调度。

1、NSOperationQueue为队列中的NSOperation分配不同的线程,测试代码如下:

 1 - (void)viewDidLoad {
 2     [super viewDidLoad];
 3     // Do any additional setup after loading the view, typically from a nib.
 4     NSLog(@"main Thread is %p",[NSThread mainThread]);
 5     [self testOperationWithQueue];
 6 }
 7 - (void)testOperationWithQueue
 8 {
 9     NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
10     NSBlockOperation *blockOperation1 = [NSBlockOperation blockOperationWithBlock:^{
11         [NSThread sleepForTimeInterval:1];
12         NSLog(@"blockOperation1:current Thread is %p",[NSThread currentThread]);
13     }];
14     NSBlockOperation *blockOperation2 = [NSBlockOperation blockOperationWithBlock:^{
15         [NSThread sleepForTimeInterval:1];
16         NSLog(@"blockOperation2:current Thread is %p",[NSThread currentThread]);
17     }];
18     NSBlockOperation *blockOperation3 = [NSBlockOperation blockOperationWithBlock:^{
19         [NSThread sleepForTimeInterval:1];
20         NSLog(@"blockOperation3:current Thread is %p",[NSThread currentThread]);
21     }];
22     [operationQueue addOperation:blockOperation1];
23     [operationQueue addOperation:blockOperation2];
24     [operationQueue addOperation:blockOperation3];
25 }
26 
27 打印结果:
28 2015-05-29 23:34:22.747 TestNSOperation[12730:1171127] main Thread is 0x7fc279f28130
29 2015-05-29 23:34:31.288 TestNSOperation[12730:1171237] blockOperation1:current Thread is 0x7fc279e0b8a0
30 2015-05-29 23:34:31.288 TestNSOperation[12730:1171238] blockOperation3:current Thread is 0x7fc279d661c0
31 2015-05-29 23:34:31.288 TestNSOperation[12730:1171235] blockOperation2:current Thread is 0x7fc279e064c0

 

从打印结果可以看出blockOperation1、blockOperation2、blockOperation3运行于不同的线程,是同时运行的,不需要等其他NSOperation,这也表明NSOperationQueue默认是并发执行。如果想要serial执行,则可以设置operationQueue.maxConcurrentOperationCount = 1;

  2、不用NSOperationQueue,也可以直接调用NSOperation的start方法,但此时NSOepration运行在当前线程上,测试代码如下:

 1 - (void)testOperationNotQueue
 2 {
 3     NSBlockOperation *blockOperation1 = [NSBlockOperation blockOperationWithBlock:^{
 4         NSLog(@"blockOperation1:current Thread is %p",[NSThread currentThread]);
 5     }];
 6     NSBlockOperation *blockOperation2 = [NSBlockOperation blockOperationWithBlock:^{
 7         NSLog(@"blockOperation2:current Thread is %p",[NSThread currentThread]);
 8     }];
 9     NSBlockOperation *blockOperation3 = [NSBlockOperation blockOperationWithBlock:^{
10         NSLog(@"blockOperation3:current Thread is %p",[NSThread currentThread]);
11     }];
12     [blockOperation1 start];
13     [blockOperation2 start];
14     [blockOperation3 start];
15 }
16 
17 //打印结果
18 2015-05-30 00:22:20.497 TestNSOperation[12968:1196358] main Thread is 0x7fb562427fd0
19 2015-05-30 00:22:20.498 TestNSOperation[12968:1196358] blockOperation1:current Thread is 0x7fb562427fd0
20 2015-05-30 00:22:20.499 TestNSOperation[12968:1196358] blockOperation2:current Thread is 0x7fb562427fd0
21 2015-05-30 00:22:20.499 TestNSOperation[12968:1196358] blockOperation3:current Thread is 0x7fb562427fd0

  从打印结果可以看出blockOperation都运行在mainThread上。

  3、NSOperation还提供了cancel功能,cancel不是强制把你的代码stop掉,只是改变了NSOperation内部的状态,该功能只能cancel掉Ready、Finish状态的NSOperation,不能cancel掉正在executing的NSOperation,测试代码如下:

 1 - (void)testCancelOperation
 2 {
 3     NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
 4     NSBlockOperation *blockOperation1 = [NSBlockOperation blockOperationWithBlock:^{
 5         NSLog(@"start blockOperation1!");
 6         [NSThread sleepForTimeInterval:10];
 7         if(blockOperation1.isCancelled)
 8         {
 9             NSLog(@"blockOperation2 cancelled!");
10             return;
11         }
12         NSLog(@"blockOperation1:current Thread is %p",[NSThread currentThread]);
13     }];
14     NSBlockOperation *blockOperation2 = [NSBlockOperation blockOperationWithBlock:^{
15         NSLog(@"blockOperation2:current Thread is %p",[NSThread currentThread]);
16     }];
17     NSBlockOperation *blockOperation3 = [NSBlockOperation blockOperationWithBlock:^{
18         NSLog(@"blockOperation3:current Thread is %p",[NSThread currentThread]);
19     }];
20     operationQueue.maxConcurrentOperationCount = 1;
21     [operationQueue addOperation:blockOperation1];
22     [operationQueue addOperation:blockOperation2];
23     [operationQueue addOperation:blockOperation3];
24     [NSThread sleepForTimeInterval:2];
25     NSLog(@"cancel blockOperation1");
26     [blockOperation1 cancel];
27     NSLog(@"cancel blockOperation2");
28     [blockOperation2 cancel];
29     NSLog(@"cancel blockOperation3");
30     [blockOperation3 cancel];
31 }
32 打印结果:
33 2015-05-30 00:27:26.311 TestNSOperation[13009:1199727] main Thread is 0x7ff02ae24e70
34 2015-05-30 00:27:26.312 TestNSOperation[13009:1199831] start blockOperation1!
35 2015-05-30 00:27:28.318 TestNSOperation[13009:1199727] cancel blockOperation1
36 2015-05-30 00:27:28.318 TestNSOperation[13009:1199727] cancel blockOperation2
37 2015-05-30 00:27:28.318 TestNSOperation[13009:1199727] cancel blockOperation3
38 2015-05-30 00:27:36.315 TestNSOperation[13009:1199831] blockOperation1:current Thread is 0x7ff02af1dec0

从打印结果可以看出不能cancel掉blockOperation1,而blockOperation2和blockOperation3则被成功地取消了。

  4、NSOpertion还可以设置依赖,这一功能解决了需要按一定次序执行的situation,不多说直接上代码:

 1 - (void)testOperationWithDependency
 2 {
 3     NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
 4     NSBlockOperation *blockOperation1 = [NSBlockOperation blockOperationWithBlock:^{
 5         NSLog(@"start blockOperation1");
 6     }];
 7     NSBlockOperation *blockOperation2 = [NSBlockOperation blockOperationWithBlock:^{
 8         [NSThread sleepForTimeInterval:2];
 9         NSLog(@"start blockOperation2");
10     }];
11     NSBlockOperation *blockOperation3 = [NSBlockOperation blockOperationWithBlock:^{
12         [NSThread sleepForTimeInterval:3];
13         NSLog(@"start blockOperation3");;
14     }];
15     [blockOperation1 addDependency:blockOperation2];
16     [blockOperation2 addDependency:blockOperation3];
17     [operationQueue addOperation:blockOperation1];
18     [operationQueue addOperation:blockOperation2];
19     [operationQueue addOperation:blockOperation3];
20 }
21 打印结果:
22 2015-05-31 18:18:06.649 TestNSOperation[15541:1510356] main Thread is 0x7fdaf9712a00
23 2015-05-31 18:18:09.654 TestNSOperation[15541:1510384] start blockOperation3
24 2015-05-31 18:18:11.660 TestNSOperation[15541:1510384] start blockOperation2
25 2015-05-31 18:18:11.660 TestNSOperation[15541:1510384] start blockOperation1

从打印的结果可以看出只有当依赖的Oepration执行完之后才开始执行自己。

  5、当NSOperation添加到NSOperationQueue中,即使进入background(超过10min)NSOperation也会执行,真的不可思议啊,不是app进入到后台后如果不开定位服务、循环播放无声音乐、VOIP就最多运行10min吗?怎么超过10min的NSOperation还能执行啊,麻烦知道的网友告知一下,万分感谢~测试代码如下:

 1 - (void)testBackgroundOperation
 2 {
 3     NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
 4     NSBlockOperation *blockOperation1 = [NSBlockOperation blockOperationWithBlock:^{
 5         [NSThread sleepForTimeInterval:11*60];
 6         NSLog(@"blockOperation1:current Thread is %p",[NSThread currentThread]);
 7     }];
 8     [operationQueue addOperation:blockOperation1];
 9 }
10 打印结果:
11 2015-05-30 01:04:40.511 TestNSOperation[13252:1219020] main Thread is 0x7faf41c0da30
12 2015-05-30 01:04:43.095 TestNSOperation[13252:1219020] applicationDidEnterBackground!
13 2015-05-30 01:15:40.526 TestNSOperation[13252:1219146] blockOperation1:current Thread is 0x7faf41e02f90

从打印结果可以看出,进入后台11min后,blockOperation1执行了,这是为什么呀!!!!

  6、疑问

  1、NSOperationQueue具体如何管理NSOperation的,网上也没找到相关文章,希望知道的朋友给个链接;2、测试中发现当NSOperationQueue是局部变量,只要NSOperation添加到NSOperationQueue中,即使程序运行到超出NSOperationQueue的生命周期外(NSOperationQueue变量自动释放了),NSOperation依然可以执行,比如如下代码,operationQueue应该是释放了,但blockOperation1、blockOperation2依然运行,其实这2个疑问都是关于NSOperationQueue如何管理NSOperation的,再次恳求知道的网友给个链接,谢谢哈~

 1 - (void)viewDidLoad {
 2     [super viewDidLoad];
 3     // Do any additional setup after loading the view, typically from a nib.
 4     NSLog(@"main Thread is %p",[NSThread mainThread]);
 5     [self testOperationLeaveLifeCycle];
 6     NSLog(@"leave operationQueue lifecycle");
 7 }
 8 - (void)testOperationLeaveLifeCycle
 9 {
10     NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
11     NSBlockOperation *blockOperation1 = [NSBlockOperation blockOperationWithBlock:^{
12         [NSThread sleepForTimeInterval:10];
13         NSLog(@"blockOperation1:current Thread is %p",[NSThread currentThread]);
14     }];
15     NSBlockOperation *blockOperation2 = [NSBlockOperation blockOperationWithBlock:^{
16         [NSThread sleepForTimeInterval:20];
17         NSLog(@"blockOperation2:current Thread is %p",[NSThread currentThread]);
18     }];
19     [operationQueue addOperation:blockOperation1];
20     [operationQueue addOperation:blockOperation2];
21 }
22 打印结果:
23 2015-05-30 01:25:49.649 TestNSOperation[13358:1228380] main Thread is 0x7ff7e27241b0
24 2015-05-30 01:25:49.650 TestNSOperation[13358:1228380] leave operationQueue lifecycle
25 2015-05-30 01:25:59.652 TestNSOperation[13358:1228482] blockOperation1:current Thread is 0x7ff7e2517d20
26 2015-05-30 01:26:09.653 TestNSOperation[13358:1228481] blockOperation2:current Thread is 0x7ff7e2608a50

 备注:上述所有的测试代码放到github上了,共勉~https://github.com/iOSGeek0829/testNSOperation

 

原文地址:https://www.cnblogs.com/NerdFooProgrammer/p/4539741.html