介绍一下开发中遇到多个任务的情况及处理方法。
1. 有两个加载图片的任务,全部加载完成后在进行相应操作,耗时操作不应该放在主线程,所以开启子线程加载,通过队列组实现:
{
// 创建队列组
dispatch_group_t group = dispatch_group_create();
// 创建并发队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
// 开子线程,任务1
dispatch_group_async(group, queue, ^{
[NSData dataWithContentsOfURL:[NSURL URLWithString:@"https://img-blog.csdn.net/20180421152137506"]];
NSLog(@"任务1 完成,线程:%@", [NSThread currentThread]);
});
// 开子线程,任务2
dispatch_group_async(group, queue, ^{
[NSData dataWithContentsOfURL:[NSURL URLWithString:@"https://img-blog.csdn.net/20170112145924755?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGVyb193cWI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center"]];
NSLog(@"任务2 完成,线程:%@", [NSThread currentThread]);
});
// 全部完成
dispatch_group_notify(group, queue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"全部完成,线程:%@", [NSThread currentThread]);
});
});
}
输出结果:
2018-05-10 19:42:16.704148+0800 AsyTaskTest[5963:308229] 任务1 完成,线程:{number = 3, name = (null)}
2018-05-10 19:42:16.725395+0800 AsyTaskTest[5963:308228] 任务2 完成,线程:{number = 4, name = (null)}
2018-05-10 19:42:16.725829+0800 AsyTaskTest[5963:308103] 全部完成,线程:{number = 1, name = main}
2. 通过NSOperation实现1中的需求,并添加依赖关系:
{
// 创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 任务1
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
[NSData dataWithContentsOfURL:[NSURL URLWithString:@"https://img-blog.csdn.net/20180421152137506"]];
NSLog(@"任务1 完成,线程:%@", [NSThread currentThread]);
}];
// 任务2
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
[NSData dataWithContentsOfURL:[NSURL URLWithString:@"https://img-blog.csdn.net/20170112145924755?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGVyb193cWI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center"]];
NSLog(@"任务2 完成,线程:%@", [NSThread currentThread]);
}];
// 添加操作依赖,注意不能循环依赖
[op1 addDependency:op2];
op1.completionBlock = ^{
NSLog(@"全部完成,线程:%@", [NSThread currentThread]);
};
// 添加操作到队列
[queue addOperation:op1];
[queue addOperation:op2];
}
输出结果:
2018-05-10 19:43:00.755428+0800 AsyTaskTest[6009:309365] 任务2 完成,线程:{number = 3, name = (null)}
2018-05-10 19:43:00.771739+0800 AsyTaskTest[6009:309362] 任务1 完成,线程:{number = 4, name = (null)}
2018-05-10 19:43:00.772045+0800 AsyTaskTest[6009:309364] 全部完成,线程:{number = 5, name = (null)}
3. 如果1中的任务本身就是异步的,按1中操作是无法实现全部加载完成后在进行相应操作:
{
NSURLSession *session = [NSURLSession sharedSession];
// 创建队列组
dispatch_group_t group = dispatch_group_create();
// 创建并发队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
// 任务1
dispatch_group_async(group, queue, ^{
NSURLSessionDataTask *task1 = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.apple.com/105/media/us/imac-pro/2018/d0b63f9b_f0de_4dea_a993_62b4cb35ca96/hero/large.mp4"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"任务1 完成,线程:%@", [NSThread currentThread]);
}];
[task1 resume];
});
// 任务2
dispatch_group_async(group, queue, ^{
NSURLSessionDataTask *task2 = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.apple.com/105/media/us/imac-pro/2018/d0b63f9b_f0de_4dea_a993_62b4cb35ca96/thumbnails/erin-sarofsky/large.mp4"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"任务2 完成,线程:%@", [NSThread currentThread]);
}];
[task2 resume];
});
// 全部完成
dispatch_group_notify(group, queue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"全部完成,线程:%@", [NSThread currentThread]);
});
});
}
输出结果:
2018-05-10 19:43:43.282177+0800 AsyTaskTest[6048:310326] 全部完成,线程:{number = 1, name = main}
2018-05-10 19:43:46.771187+0800 AsyTaskTest[6048:310361] 任务2 完成,线程:{number = 3, name = (null)}
2018-05-10 19:43:47.061490+0800 AsyTaskTest[6048:310364] 任务1 完成,线程:{number = 4, name = (null)}
4. 通过dispatch_group_enter、dispatch_group_leave实现3的需求:
{
NSURLSession *session = [NSURLSession sharedSession];
// 创建队列组
dispatch_group_t group = dispatch_group_create();
// 任务1
dispatch_group_enter(group);
NSURLSessionDataTask *task1 = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.apple.com/105/media/us/imac-pro/2018/d0b63f9b_f0de_4dea_a993_62b4cb35ca96/hero/large.mp4"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"任务1 完成,线程:%@", [NSThread currentThread]);
dispatch_group_leave(group);
}];
[task1 resume];
// 任务2
dispatch_group_enter(group);
NSURLSessionDataTask *task2 = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.apple.com/105/media/us/imac-pro/2018/d0b63f9b_f0de_4dea_a993_62b4cb35ca96/thumbnails/erin-sarofsky/large.mp4"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"任务2 完成,线程:%@", [NSThread currentThread]);
dispatch_group_leave(group);
}];
[task2 resume];
// 全部完成
dispatch_group_notify(group, dispatch_get_main_queue(), ^(){
NSLog(@"全部完成,线程:%@", [NSThread currentThread]);
});
}
输出结果:
2018-05-10 19:44:30.653594+0800 AsyTaskTest[6102:311543] 任务2 完成,线程:{number = 3, name = (null)}
2018-05-10 19:44:30.868703+0800 AsyTaskTest[6102:311539] 任务1 完成,线程:{number = 4, name = (null)}
2018-05-10 19:44:30.868897+0800 AsyTaskTest[6102:311509] 全部完成,线程:{number = 1, name = main}
5. 通过信号量实现3的需求:
{
// 初始化信号量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
NSURLSession *session = [NSURLSession sharedSession];
// 创建队列组
dispatch_group_t group = dispatch_group_create();
// 创建并发队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
// 任务1
dispatch_group_async(group, queue, ^{
NSURLSessionDataTask *task1 = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.apple.com/105/media/us/imac-pro/2018/d0b63f9b_f0de_4dea_a993_62b4cb35ca96/hero/large.mp4"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"任务1 完成,线程:%@", [NSThread currentThread]);
// 发送信号,使信号量+1
dispatch_semaphore_signal(semaphore);
}];
[task1 resume];
});
// 信号量等于0时会一直等待,大于0时正常执行,并让信号量-1
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// 任务2
dispatch_group_async(group, queue, ^{
NSURLSessionDataTask *task2 = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.apple.com/105/media/us/imac-pro/2018/d0b63f9b_f0de_4dea_a993_62b4cb35ca96/thumbnails/erin-sarofsky/large.mp4"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"任务2 完成,线程:%@", [NSThread currentThread]);
dispatch_semaphore_signal(semaphore);
}];
[task2 resume];
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// 全部完成
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"全部完成,线程:%@", [NSThread currentThread]);
});
}
输出结果:
2018-05-10 19:45:14.503833+0800 AsyTaskTest[6149:312567] 任务1 完成,线程:{number = 3, name = (null)}
2018-05-10 19:45:14.631690+0800 AsyTaskTest[6149:312567] 任务2 完成,线程:{number = 3, name = (null)}
2018-05-10 19:45:14.636026+0800 AsyTaskTest[6149:312507] 全部完成,线程:{number = 1, name = main}
这里做一下解释:
执行第3行代码,初始化信号量为0;
执行第13行代码,异步执行任务1;
执行第22行代码,信号量为0,进入等待,不会往后执行代码,任务1完成,17行代码执行使信号量+1变为1,通过22行代码,信号量-1变为0;
执行第25行代码,异步执行任务2;
执行第32行代码,信号量为0,进入等待,不会往后执行代码,任务2完成,28行代码执行使信号量+1变为1,通过32行代码,信号量-1变为0;
执行第36行代码,全部完成。
可以看出,这样执行,是先执行任务1,然后执行任务2。如果想同时执行任务1和任务2,只需要把22行代码移到33行位置。
注意一点:使用信号量,dispatch_semaphore_signal和dispatch_semaphore_wait需要成对使用,不然会造成crash。