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