接着看NSOperation、NSOperationQueue线程间的通信:

应用场景:比如我们经常把一些耗时的操作比如下载图片放在子线程,那么当这个完成之后,我们就需要回到主线程,这个时候就需要用到线程间的通信。

来看下代码:

//线程间通信
-(void)communication{
//1.创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init]; //2.添加操作
[queue addOperationWithBlock:^{
//异步进行的耗时操作
for (int i=0; i<2; ++i) {
[NSThread sleepForTimeInterval:2.0];//模拟耗时操作
NSLog(@"1----%@",[NSThread currentThread]);//打印当前线程
} //回到主线程
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
//进行UI刷新操作
for (int i=0; i<2; ++i) {
[NSThread sleepForTimeInterval:2.0];
NSLog(@"2----%@",[NSThread currentThread]);
}
}];
}];
}

  来看打印:

2019-04-09 11:25:34.507056+0800 MyNSOperation[2488:37353] 1----<NSThread: 0x600000082840>{number = 3, name = (null)}
2019-04-09 11:25:36.510730+0800 MyNSOperation[2488:37353] 1----<NSThread: 0x600000082840>{number = 3, name = (null)}
2019-04-09 11:25:38.513231+0800 MyNSOperation[2488:37047] 2----<NSThread: 0x6000000e29c0>{number = 1, name = main}
2019-04-09 11:25:40.516515+0800 MyNSOperation[2488:37047] 2----<NSThread: 0x6000000e29c0>{number = 1, name = main}

  可以看到,在子线程进行异步操作后,回到了主线程。

再来看下NSOperation与NSOperationQueue的线程同步与线程安全

我们来看一个经典的卖火车票的例子,假如我们不考虑线程安全是啥情况。

/*
非线程安全,不用锁 */
-(void)initTicketStatusNotSafe{
NSLog(@"currentThread---%@",[NSThread currentThread]);
self.ticketCount = 50;
//1.创建queue1,queue1代表北京售票窗口
NSOperationQueue *queue1 = [[NSOperationQueue alloc] init];
queue1.maxConcurrentOperationCount = 1;
//2.创建queue2.queue2代表上海售票窗口
NSOperationQueue *queue2 = [[NSOperationQueue alloc] init];
queue2.maxConcurrentOperationCount = 1;
//3.创建卖票的操作
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
[self saleTicketNotSafe];
}];
//4.创建卖票操作
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
[self saleTicketNotSafe];
}]; //5.开始卖票
[queue1 addOperation:op1];
[queue2 addOperation:op2];
} //售卖火车票
-(void)saleTicketNotSafe{
while(true){
if (self.ticketCount>0) {
//如果还有票,就继续卖
self.ticketCount--;
NSLog(@"%@",[NSString stringWithFormat:@"剩余票数:%d 窗口%@",self.ticketCount,[NSThread currentThread]]);
[NSThread sleepForTimeInterval:2.0];
}else{
NSLog(@"所有的火车票已售完");
break;
}
}
}

  看打印情况:

2019-04-09 11:57:13.000691+0800 MyNSOperation[3785:58834] currentThread---<NSThread: 0x600002ad1240>{number = 1, name = main}
2019-04-09 11:57:13.006247+0800 MyNSOperation[3785:58934] 剩余票数:49 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:57:13.006501+0800 MyNSOperation[3785:58932] 剩余票数:48 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:15.011866+0800 MyNSOperation[3785:58934] 剩余票数:47 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:57:15.011959+0800 MyNSOperation[3785:58932] 剩余票数:46 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:17.015980+0800 MyNSOperation[3785:58934] 剩余票数:45 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:57:17.015980+0800 MyNSOperation[3785:58932] 剩余票数:45 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:19.020346+0800 MyNSOperation[3785:58934] 剩余票数:43 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:57:19.020354+0800 MyNSOperation[3785:58932] 剩余票数:44 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:21.026026+0800 MyNSOperation[3785:58934] 剩余票数:42 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:57:21.026112+0800 MyNSOperation[3785:58932] 剩余票数:41 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:23.026638+0800 MyNSOperation[3785:58934] 剩余票数:39 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:57:23.026648+0800 MyNSOperation[3785:58932] 剩余票数:40 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:25.031698+0800 MyNSOperation[3785:58934] 剩余票数:38 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:57:25.031763+0800 MyNSOperation[3785:58932] 剩余票数:37 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:27.032664+0800 MyNSOperation[3785:58934] 剩余票数:36 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:57:27.032664+0800 MyNSOperation[3785:58932] 剩余票数:35 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:29.036969+0800 MyNSOperation[3785:58934] 剩余票数:34 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:57:29.037052+0800 MyNSOperation[3785:58932] 剩余票数:33 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:31.041413+0800 MyNSOperation[3785:58934] 剩余票数:31 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:57:31.041416+0800 MyNSOperation[3785:58932] 剩余票数:32 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:33.044314+0800 MyNSOperation[3785:58934] 剩余票数:30 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:57:33.044314+0800 MyNSOperation[3785:58932] 剩余票数:29 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:35.049399+0800 MyNSOperation[3785:58934] 剩余票数:28 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:57:35.049449+0800 MyNSOperation[3785:58932] 剩余票数:28 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:37.054456+0800 MyNSOperation[3785:58934] 剩余票数:27 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:57:37.054456+0800 MyNSOperation[3785:58932] 剩余票数:27 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:39.057780+0800 MyNSOperation[3785:58934] 剩余票数:26 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:57:39.057780+0800 MyNSOperation[3785:58932] 剩余票数:26 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:41.058922+0800 MyNSOperation[3785:58932] 剩余票数:25 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:41.058922+0800 MyNSOperation[3785:58934] 剩余票数:25 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:57:43.062224+0800 MyNSOperation[3785:58932] 剩余票数:24 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:43.062312+0800 MyNSOperation[3785:58934] 剩余票数:23 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:57:45.066320+0800 MyNSOperation[3785:58934] 剩余票数:21 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:57:45.066320+0800 MyNSOperation[3785:58932] 剩余票数:22 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:47.070458+0800 MyNSOperation[3785:58934] 剩余票数:20 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:57:47.070470+0800 MyNSOperation[3785:58932] 剩余票数:20 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:49.072585+0800 MyNSOperation[3785:58934] 剩余票数:19 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:57:49.072585+0800 MyNSOperation[3785:58932] 剩余票数:18 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:51.076732+0800 MyNSOperation[3785:58934] 剩余票数:17 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:57:51.076732+0800 MyNSOperation[3785:58932] 剩余票数:16 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:53.081887+0800 MyNSOperation[3785:58932] 剩余票数:15 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:53.081887+0800 MyNSOperation[3785:58934] 剩余票数:15 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:57:55.084748+0800 MyNSOperation[3785:58934] 剩余票数:14 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:57:55.084752+0800 MyNSOperation[3785:58932] 剩余票数:13 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:57.087508+0800 MyNSOperation[3785:58934] 剩余票数:11 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:57:57.087508+0800 MyNSOperation[3785:58932] 剩余票数:12 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:59.092573+0800 MyNSOperation[3785:58932] 剩余票数:10 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:57:59.092573+0800 MyNSOperation[3785:58934] 剩余票数:10 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:58:01.096928+0800 MyNSOperation[3785:58934] 剩余票数:8 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:58:01.096928+0800 MyNSOperation[3785:58932] 剩余票数:9 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:58:03.102158+0800 MyNSOperation[3785:58934] 剩余票数:6 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:58:03.102075+0800 MyNSOperation[3785:58932] 剩余票数:7 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:58:05.106820+0800 MyNSOperation[3785:58934] 剩余票数:5 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:58:05.106821+0800 MyNSOperation[3785:58932] 剩余票数:4 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:58:07.110551+0800 MyNSOperation[3785:58932] 剩余票数:3 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:58:07.110571+0800 MyNSOperation[3785:58934] 剩余票数:3 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:58:09.115589+0800 MyNSOperation[3785:58932] 剩余票数:1 窗口<NSThread: 0x600002ab8040>{number = 4, name = (null)}
2019-04-09 11:58:09.115589+0800 MyNSOperation[3785:58934] 剩余票数:2 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:58:11.117467+0800 MyNSOperation[3785:58932] 所有的火车票已售完
2019-04-09 11:58:11.117476+0800 MyNSOperation[3785:58934] 剩余票数:0 窗口<NSThread: 0x600002a87c00>{number = 3, name = (null)}
2019-04-09 11:58:13.120972+0800 MyNSOperation[3785:58934] 所有的火车票已售完

  可以看到,有多个票数得到的是重复的,错乱的。

所有我们要解决线程安全的问题,使用锁。在一个线程操作一个资源的时候,给这个资源加锁,不允许其他线程进行操作。IOS中实现线程加锁的方式是有很多种的。比如@synchronized,NSLock,NSRecursiveLock,NSConditionLock等等多种方式。我们这里使用NSLock的方式来给线程加锁。

我们来看下使用线程安全的代码:

/*
线程安全的代码,使用NSLock锁
初始化火车票数量,卖票窗口(线程安全),并开始卖票
*/
-(void)initTicketStatusSafe{
NSLog(@"currentThread----%@",[NSThread currentThread]);
self.ticketCount = 50;
self.lock = [[NSLock alloc] init];
//1.创建queue1,queue1代表北京售票窗口
NSOperationQueue *queue1 = [[NSOperationQueue alloc] init];
queue1.maxConcurrentOperationCount = 1; //2.创建queue2,queue2代表上海售票窗口
NSOperationQueue *queue2 = [[NSOperationQueue alloc] init];
queue2.maxConcurrentOperationCount = 1; //3.创建卖票操作op1
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
[self saleTicketSafe];
}];
//4.创建卖票操作op2
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
[self saleTicketSafe];
}];
//5.添加操作,开始卖票
[queue1 addOperation:op1];
[queue2 addOperation:op2];
} //售卖火车票(线程安全)
-(void)saleTicketSafe{
while (true) {
//加锁
[self.lock lock];
if(self.ticketCount>0){
//如果还有票的话,就继续卖票
self.ticketCount--;
NSLog(@"%@",[NSString stringWithFormat:@"剩余票数:%d,窗口:%@",self.ticketCount,[NSThread currentThread]]);
[NSThread sleepForTimeInterval:2.0];
}
//解锁
[self.lock unlock];
if(self.ticketCount<=0){
NSLog(@"所有票已经卖完");
break;
}
}
}

  来看打印:

2019-04-09 15:29:44.182861+0800 MyNSOperation[10565:159368] currentThread----<NSThread: 0x60000063f780>{number = 1, name = main}
2019-04-09 15:29:44.186854+0800 MyNSOperation[10565:159459] 剩余票数:49,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:29:46.187749+0800 MyNSOperation[10565:159449] 剩余票数:48,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:29:48.190175+0800 MyNSOperation[10565:159459] 剩余票数:47,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:29:50.193962+0800 MyNSOperation[10565:159449] 剩余票数:46,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:29:52.199454+0800 MyNSOperation[10565:159459] 剩余票数:45,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:29:54.203206+0800 MyNSOperation[10565:159449] 剩余票数:44,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:29:56.207794+0800 MyNSOperation[10565:159459] 剩余票数:43,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:29:58.213412+0800 MyNSOperation[10565:159449] 剩余票数:42,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:30:00.214024+0800 MyNSOperation[10565:159459] 剩余票数:41,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:30:02.219388+0800 MyNSOperation[10565:159449] 剩余票数:40,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:30:04.224701+0800 MyNSOperation[10565:159459] 剩余票数:39,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:30:06.230349+0800 MyNSOperation[10565:159449] 剩余票数:38,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:30:08.233439+0800 MyNSOperation[10565:159459] 剩余票数:37,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:30:10.236390+0800 MyNSOperation[10565:159449] 剩余票数:36,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:30:12.239285+0800 MyNSOperation[10565:159459] 剩余票数:35,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:30:14.242919+0800 MyNSOperation[10565:159449] 剩余票数:34,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:30:16.246876+0800 MyNSOperation[10565:159459] 剩余票数:33,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:30:18.252321+0800 MyNSOperation[10565:159449] 剩余票数:32,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:30:20.253964+0800 MyNSOperation[10565:159459] 剩余票数:31,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:30:22.254687+0800 MyNSOperation[10565:159449] 剩余票数:30,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:30:24.255193+0800 MyNSOperation[10565:159459] 剩余票数:29,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:30:26.256679+0800 MyNSOperation[10565:159449] 剩余票数:28,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:30:28.261450+0800 MyNSOperation[10565:159459] 剩余票数:27,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:30:30.262594+0800 MyNSOperation[10565:159449] 剩余票数:26,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:30:32.267232+0800 MyNSOperation[10565:159459] 剩余票数:25,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:30:34.271705+0800 MyNSOperation[10565:159449] 剩余票数:24,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:30:36.275290+0800 MyNSOperation[10565:159459] 剩余票数:23,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:30:38.278967+0800 MyNSOperation[10565:159449] 剩余票数:22,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:30:40.284568+0800 MyNSOperation[10565:159459] 剩余票数:21,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:30:42.288319+0800 MyNSOperation[10565:159449] 剩余票数:20,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:30:44.293916+0800 MyNSOperation[10565:159459] 剩余票数:19,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:30:46.298411+0800 MyNSOperation[10565:159449] 剩余票数:18,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:30:48.301898+0800 MyNSOperation[10565:159459] 剩余票数:17,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:30:50.307369+0800 MyNSOperation[10565:159449] 剩余票数:16,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:30:52.309734+0800 MyNSOperation[10565:159459] 剩余票数:15,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:30:54.312124+0800 MyNSOperation[10565:159449] 剩余票数:14,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:30:56.313696+0800 MyNSOperation[10565:159459] 剩余票数:13,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:30:58.315219+0800 MyNSOperation[10565:159449] 剩余票数:12,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:31:00.317869+0800 MyNSOperation[10565:159459] 剩余票数:11,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:31:02.322281+0800 MyNSOperation[10565:159449] 剩余票数:10,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:31:04.326708+0800 MyNSOperation[10565:159459] 剩余票数:9,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:31:06.332550+0800 MyNSOperation[10565:159449] 剩余票数:8,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:31:08.336064+0800 MyNSOperation[10565:159459] 剩余票数:7,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:31:10.341717+0800 MyNSOperation[10565:159449] 剩余票数:6,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:31:12.342312+0800 MyNSOperation[10565:159459] 剩余票数:5,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:31:14.347439+0800 MyNSOperation[10565:159449] 剩余票数:4,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:31:16.348122+0800 MyNSOperation[10565:159459] 剩余票数:3,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:31:18.352838+0800 MyNSOperation[10565:159449] 剩余票数:2,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:31:20.355310+0800 MyNSOperation[10565:159459] 剩余票数:1,窗口:<NSThread: 0x600000663740>{number = 3, name = (null)}
2019-04-09 15:31:22.358857+0800 MyNSOperation[10565:159449] 剩余票数:0,窗口:<NSThread: 0x600000658bc0>{number = 4, name = (null)}
2019-04-09 15:31:24.363256+0800 MyNSOperation[10565:159449] 所有票已经卖完
2019-04-09 15:31:24.363263+0800 MyNSOperation[10565:159459] 所有票已经卖完

  可以看出,在使用了线程安全机制之后,票数正常了。

IOS高级开发之多线程(五)NSOperation 2的更多相关文章

  1. IOS高级开发之多线程(四)NSOperation

    1.什么是NSOperation,NSOperationQueue? NSOperation是一个抽象的基类,表示一个独立的计算单元,可以为子类提供有用且线程安全的建立状态,优先级,依赖和取消等操作. ...

  2. ios高级开发之多线程(三)GCD技术

    GCD是基于C的API,它是libdispatch的的市场名称.而libdispatch作为Apple公司的一个库,为并发代码在多核硬件(跑IOS或者OS X)上执行提供有力支持. 那么我们为什么要用 ...

  3. ios高级开发之多线程(二)NSThread技术

    多线程技术是有多套解决方案的,那么我们该如何选择呢? 技术方案 简介 语言 线程生命周期 使用频率 pthread 1.一套通用的多线程API 2.适用于UNIX,linux,windows等 3.跨 ...

  4. ios高级开发之多线程(一)

    1.概念: 多线程(multithreading)到底是什么呢,它是指在软件或者硬件上实现多个线程并发执行的技术.具有多线程能力的计算机因有硬件的支持,而能够在同一时间执行多个线程,进而提升整体处理性 ...

  5. 移动开发在路上-- IOS移动开发系列 多线程二

    最近太忙没太多的时间,忙碌的码农生活空下来一点时间,都会挤出来看一些技术或者咨询的文章,废话不多说,直奔主题. 接着上一次的继续说. 定时器在多线程的使用 NSRunLoop 是线程相关的基础框架的一 ...

  6. iOS 11开发教程(五)iOS11模拟器介绍二

    iOS 11开发教程(五)iOS11模拟器介绍二 3.iOS11模拟器中设置语言 对于不同国家的人来说,使用到的语言是不一样的.一般情况下iOS11模拟器默认使用的English(英语).对于英文不好 ...

  7. (转发)IOS高级开发~Runtime(四)

    用C代替OC: #import <objc/runtime.h> #import <objc/message.h> #import <stdio.h> extern ...

  8. (转发)IOS高级开发~Runtime(三)

    11.系统类的方法实现部分替换 - (void) methodExchange { Method m1 = class_getInstanceMethod([NSStringclass],@selec ...

  9. (转发)IOS高级开发~Runtime(二)

    一些公用类: @interface ClassCustomClass :NSObject{ NSString *varTest1; NSString *varTest2; NSString *varT ...

随机推荐

  1. iOS的签名机制

    1.从keychain里“从这证书颁发机构请求证书”,这样就在本地生成了一对公私钥,保存的CertificateSigningRequest就是公钥,私钥保存在本地电脑里. 2.苹果自己有一对固定的公 ...

  2. SQL对照LinQ的基本语句

    查询全表: string sql = "SELECT * FROM UserInfo"; var lamAll = db.UserInfo; var LinAll = from u ...

  3. Spring Batch(三) Job Launcher、ItemReader、ItemProcessor、ItemWriter各个实现类和用途

    内容来自<Spring Batch 批处理框架>,作者:刘相. 1.JobLauncher JobLauncher(作业调度器)是SpringBatch框架提供的运行Job的能力.用过给定 ...

  4. Spark SQL历险记

    现在的spark sql编程通常使用scala api 以及 java api的方式,相比于直接使用 spark sql语句,spark api灵活很多,毕竟可以基于dataset以及rdd两种方式进 ...

  5. 68.jq---tab选项实现网页定点切换

    {volist name="list" id="vo"}<div class="nav_div" style="positi ...

  6. 计算机网络网络层的IP地址划分及子码

    现在在网络层,即就是TCP/IP协议里的网际互联层,最流行IP协议的就是IPV4.其中IP地址的格式是由32位二进制数字表示的,通常为了人们阅读习惯,将其转换成点分十进制来表示,如:192.168.1 ...

  7. Qt如何在QTabWidget上绘图

    Qt绘图事件必须在paintEvent事件下绘图,这样导致我们在向Qt设计师界面上拖拽的控件绘图时,造成了很大的麻烦. 我们不能在拖拽的控件上写paintEvent函数,但是可以自定义一个类,继承某一 ...

  8. Java设计模式之动态代理

    关于Proxy: 1,他是所有动态代理的父类: 2,他可以用作创建动态代理类和动态代理对象: 3,JDK中自带的动态代理. 1,首先创建一个接口,方法申明如下: package com.proxy; ...

  9. codeforces-4

    这题使用到了类似于双数据 Maximal Continuous #include<iostream> #include<algorithm> #include<stdio ...

  10. 【转】数据处理常用的sql语句整理

    一下语句都是基于 mysql数据库 查询是否使用索引 explain  select * FROM t_table1; 结果列的含义: table:此次查询操作是关联哪张数据表 type:连接查询操作 ...