ios中得多线程技术主要使用3种:NSThread、NSOperation和GCD
一、NSThread: 最轻量级方法,但是不安全需要手动加锁,需要自己管理生命周期
NSThread的使用方法有2种:
// 第一种,需要start
1 NSThread *th1 = [[NSThread alloc] initWithTarget:self selector:@selector(btnClick) object:nil]; 2 [th1 setName:@"线程1"]; 3 [th1 start];
// 第二种
1 [NSThread detachNewThreadSelector:@selector(btnClick) toTarget:self withObject:nil];
因为NSThread使用不安全,我们需要给它加锁(主要的实现代码):
1 @property (nonatomic,assign) NSInteger fruits; 2 @property (nonatomic,strong) NSLock *lock; 3 - (void)viewDidLoad 4 { 5 [super viewDidLoad]; 6 7 _lock = [[NSLock alloc] init]; 8 _fruits = 50; 9 } 10 11 - (void)btnClick 12 { 13 @synchronized(_lock){ // 加锁 14 15 while (_fruits > 0) { 16 17 NSLog(@"当前线程为:%@ , 剩余票数为:%d",[NSThread currentThread], _fruits); 18 19 _fruits--; 20 } 21 } 22 }
二、GCD:(Grand Central Dispatch)是一种多核编码技术,用纯C语言编写。
异步:具备开启线程的功能
同步:不具备开启线程的功能
并行队列:多个任务可以同时执行
串行队列:执行完一个任务后再执行下一个任务
下面来进行用代码说明:
1 // 自定义异步方法 2 - (void)async:(dispatch_queue_t)queue 3 { 4 // 异步执行 5 dispatch_async(queue, ^{ 6 7 NSLog(@"im1-%@",[NSThread currentThread]); 8 }); 9 dispatch_async(queue, ^{ 10 11 NSLog(@"im2-%@",[NSThread currentThread]); 12 }); 13 dispatch_async(queue, ^{ 14 15 NSLog(@"im3-%@",[NSThread currentThread]); 16 }); 17 dispatch_async(queue, ^{ 18 19 NSLog(@"im4-%@",[NSThread currentThread]); 20 }); 21 22 }
1 // 自定义同步方法 2 - (void)sync:(dispatch_queue_t)queue 3 { 4 // 同步执行 5 dispatch_sync(queue, ^{ 6 7 NSLog(@"im1-%@",[NSThread currentThread]); 8 }); 9 dispatch_sync(queue, ^{ 10 11 NSLog(@"im2-%@",[NSThread currentThread]); 12 }); 13 dispatch_sync(queue, ^{ 14 15 NSLog(@"im3-%@",[NSThread currentThread]); 16 }); 17 dispatch_sync(queue, ^{ 18 19 NSLog(@"im4-%@",[NSThread currentThread]); 20 }); 21 22 }
调用异步执行方法:
1 // 创建一个全局并行队列 2 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 3 4 // 异步执行 5 [self async:queue];
最终的结果为:开启了四个线程,并且执行顺序是不定
1 2015-04-02 16:29:20.438 GCD[4398:1f07] im3-<NSThread: 0x7177ee0>{name = (null), num = 5} 2 2015-04-02 16:29:20.432 GCD[4398:1303] im1-<NSThread: 0x7177d70>{name = (null), num = 3} 3 2015-04-02 16:29:20.440 GCD[4398:4307] im4-<NSThread: 0x7178490>{name = (null), num = 6} 4 2015-04-02 16:29:20.432 GCD[4398:1a03] im2-<NSThread: 0x75429f0>{name = (null), num = 4}
1 // 创建一个全局串行队列 2 dispatch_queue_t queue = dispatch_queue_create("wys", NULL); 3 4 // 异步执行 5 [self async:queue];
最终的结果为:开启了一个线程,执行顺序为从上往下依次执行
1 2015-04-02 16:32:19.415 GCD[4442:1303] im1-<NSThread: 0x71631a0>{name = (null), num = 3} 2 2015-04-02 16:32:19.428 GCD[4442:1303] im2-<NSThread: 0x71631a0>{name = (null), num = 3} 3 2015-04-02 16:32:19.437 GCD[4442:1303] im3-<NSThread: 0x71631a0>{name = (null), num = 3} 4 2015-04-02 16:32:19.450 GCD[4442:1303] im4-<NSThread: 0x71631a0>{name = (null), num = 3}
调用主队列执行方法:
1 // 创建主队列 2 dispatch_queue_t queue = dispatch_get_main_queue(); 3 4 // 异步执行 5 [self async:queue];
最红的结果为:顺序执行并且不开启线程,在主线程中执行
1 2015-04-02 16:35:45.320 GCD[4484:c07] im1-<NSThread: 0x71560c0>{name = (null), num = 1} 2 2015-04-02 16:35:45.333 GCD[4484:c07] im2-<NSThread: 0x71560c0>{name = (null), num = 1} 3 2015-04-02 16:35:45.339 GCD[4484:c07] im3-<NSThread: 0x71560c0>{name = (null), num = 1} 4 2015-04-02 16:35:45.347 GCD[4484:c07] im4-<NSThread: 0x71560c0>{name = (null), num = 1}
1 // 创建主队列 2 dispatch_queue_t queue = dispatch_get_main_queue(); 3 4 NSLog(@"start"); 5 6 // 同步执行 7 [self sync:queue]; 8 9 NSLog(@"end");
最终的结果为:执行到start就卡住了,不能往下执行
1 2015-04-02 16:38:12.856 GCD[4514:c07] start
调用同步执行方法:
1 // 创建全局并行队列 2 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 3 4 // 同步执行 5 [self sync:queue];
最终的结果为:不开启线程,并且顺序执行,直接主线程执行
1 2015-04-02 16:41:27.448 GCD[4555:c07] im1-<NSThread: 0x71133c0>{name = (null), num = 1} 2 2015-04-02 16:41:27.458 GCD[4555:c07] im2-<NSThread: 0x71133c0>{name = (null), num = 1} 3 2015-04-02 16:41:27.468 GCD[4555:c07] im3-<NSThread: 0x71133c0>{name = (null), num = 1} 4 2015-04-02 16:41:27.472 GCD[4555:c07] im4-<NSThread: 0x71133c0>{name = (null), num = 1}
1 // 创建串行队列 2 dispatch_queue_t queue = dispatch_queue_create("wys", NULL); 3 4 // 同步执行 5 [self sync:queue];
最终的结果为:不开启线程,并且顺序执行,直接主线程执行
1 2015-04-02 16:43:40.609 GCD[4589:c07] im1-<NSThread: 0x713e570>{name = (null), num = 1} 2 2015-04-02 16:43:40.621 GCD[4589:c07] im2-<NSThread: 0x713e570>{name = (null), num = 1} 3 2015-04-02 16:43:40.626 GCD[4589:c07] im3-<NSThread: 0x713e570>{name = (null), num = 1} 4 2015-04-02 16:43:40.634 GCD[4589:c07] im4-<NSThread: 0x713e570>{name = (null), num = 1}
多线程之间的通信:UI界面的更新一定要在主线程中执行
1 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 全局并行队列异步执行 2 3 4 NSLog(@"全局并行队列异步执行 - %@",[NSThread currentThread]); 5 6 // 获取网络图片数据 7 NSString *str = @"https://ss0.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3384245408,2851245305&fm=21&gp=0.jpg"; 8 NSURL *url = [NSURL URLWithString:str]; 9 10 NSData *data = [NSData dataWithContentsOfURL:url]; 11 12 UIImage *image = [UIImage imageWithData:data]; 13 14 dispatch_async(dispatch_get_main_queue(), ^{ // 主线程异步执行 15 16 NSLog(@"主线程异步执行 - %@",[NSThread currentThread]); 17 18 // 更新界面 19 [_im1 setImage:image]; 20 }); 21 22 });
最终的结果为:
2015-04-03 11:37:08.513 GCD[1095:1303] 全局并行队列异步执行 -<NSThread: 0x754c530>{name = (null), num = 3} 2015-04-03 11:37:10.657 GCD[1095:c07] 主线程异步执行 -<NSThread: 0x7132c80>{name = (null), num = 1}
利用多线程来实现延时执行:
1、利用GCD
1 double delayInSeconds = 2.0; // 延时时长 2 dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); 3 dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ // 在主线程中执行 4 5 NSLog(@"%@",[NSThread currentThread]); 6 7 // 更新界面 8 [_im1 setImage:image]; 9 10 });
2、利用此方法,performSelector为你要调用的方法,withObject为你要传得值,afterDelay为延时时长
1 [self performSelector:@selector(downLoad) withObject:nil afterDelay:0.5f];
队列组:
1 dispatch_group_t group = dispatch_group_create(); 2 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 3 4 dispatch_group_async(group, queue, ^{ 5 6 // 代码1 7 }); 8 9 dispatch_group_async(group, queue, ^{ 10 11 // 代码2 12 }); 13 14 dispatch_group_notify(group, queue, ^{ 15 16 // 执行完代码1和代码2后,再执行此方法 17 });
三、NSOperation:基于GCD,能控制最大并发线程数,主要有2个类:NSInvocationOperation和NSBlockOperation
其步骤为: 创建队列、添加操作、将操作添加到队列
A、NSInvocationOperation:
1 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 2 { 3 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 4 5 NSInvocationOperation *invo = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(buy) object:nil]; 6 7 8 [queue addOperation:invo]; 9 10 } 11 12 - (void)buy 13 { 14 NSLog(@"%@",[NSThread currentThread]); 15 }
最后的结果为:开启了一个线程
1 2015-04-03 14:58:54.060 op1[2631:1e07] <NSThread: 0x71a6de0>{name = (null), num = 3}
B、NSBlockOperation
1 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 2 3 NSBlockOperation *b1 = [NSBlockOperation blockOperationWithBlock:^{ 4 5 NSLog(@"111--%@",[NSThread currentThread]); 6 }]; 7 NSBlockOperation *b2 = [NSBlockOperation blockOperationWithBlock:^{ 8 9 NSLog(@"222--%@",[NSThread currentThread]); 10 }]; 11 NSBlockOperation *b3 = [NSBlockOperation blockOperationWithBlock:^{ 12 13 NSLog(@"333--%@",[NSThread currentThread]); 14 }]; 15 16 17 18 [queue addOperation:b1]; 19 [queue addOperation:b2]; 20 [queue addOperation:b3];
最后的结果为:开启了三个线程,自动异步执行
1 2015-04-03 15:15:59.897 op1[2798:1a03] 111--<NSThread: 0x7544fa0>{name = (null), num = 3} 2 2015-04-03 15:15:59.901 op1[2798:4307] 222--<NSThread: 0x71506f0>{name = (null), num = 4} 3 2015-04-03 15:15:59.902 op1[2798:1303] 333--<NSThread: 0x7545e60>{name = (null), num = 5}
设置依赖:
1 // 设置依赖 ,b2依赖b1,b3依赖b2,所以执行顺序为,b1->b2->b3 2 [b2 addDependency:b1]; 3 [b3 addDependency:b2];
设置队列的最大并发数量
1 // 设置最大并发(最多同时并发执行3个任务) 2 queue.maxConcurrentOperationCount = 2;
C、主队列
1 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 2 3 [queue addOperationWithBlock:^{ 4 5 NSLog(@"-------%@",[NSThread currentThread]); 6 7 // 获取网络图片数据 8 NSString *str = @"https://ss0.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3384245408,2851245305&fm=21&gp=0.jpg"; 9 NSURL *url = [NSURL URLWithString:str]; 10 11 NSData *data = [NSData dataWithContentsOfURL:url]; 12 13 UIImage *image = [UIImage imageWithData:data]; 14 15 [[NSOperationQueue mainQueue] addOperationWithBlock:^{ // 主队列 16 17 NSLog(@"******%@",[NSThread currentThread]); 18 19 // 更新界面 20 [_im1 setImage:image]; 21 }]; 22 }];
最后的结果为:
1 2015-04-03 15:27:16.077 op1[2916:1c03] -------<NSThread: 0x71613e0>{name = (null), num = 3} 2 2015-04-03 15:27:17.593 op1[2916:c07] ******<NSThread: 0x7134fa0>{name = (null), num = 1} // 主队列