iOS 多任务全部执行完后再执行操作 —— HERO博客

介绍一下开发中遇到多个任务的情况及处理方法。

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。

你可能感兴趣的:(iOS,Objective-C技术分享)