网络iOS Developer

iOS GCD基本使用及详解

2017-03-21  本文已影响0人  丶过客匆匆

GCD的基本函数:


队列:

GCD 用dispatch queue来处理代码块,这些队列管理你提供给 GCD 的任务并执行这些任务。这就保证了第一个被添加到队列里的任务会是队列中第一个开始的任务,而第二个被添加的任务将第二个开始,如此直到队列的终点。

//获取主队列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
//使用dispatch_get_global_queue()获取全局并发队列,第一个参数是队列优先级,第二个参数传0.
dispatch_queue_t otherQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
/** 
  * 使用 dispatch_queue_create 初始化 concurrentQueue 为一个并发队列。
  * 第一个参数是队列标识;第二个参数指定你的队列是串行还是并发。设为NULL时默认是DISPATCH_QUEUE_SERIAL,将创建串行队列.
  * 在必要情况下,你可以将其设置为DISPATCH_QUEUE_CONCURRENT来创建自定义并行队列.
 */
dispatch_queue_t myQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);

同步和异步:

//同步函数,在当前线程执行(不开启新的线程)
dispatch_sync(otherQueue, ^{
    NSLog(@"同步:%@",[NSThread currentThread]);
});

//异步函数,开启子线程执行
dispatch_async(otherQueue, ^{
    NSLog(@"异步:%@",[NSThread currentThread]);
});
打印:
[15276:540462] 同步:<NSThread: 0x600000068680>{number = 1, name = main}
[15276:540519] 异步:<NSThread: 0x600000074a80>{number = 3, name = (null)}

串行队列:

一个任务执行完毕后,再执行下一个任务

// 1.使用 dispatch_queue_creat()创建串行队列
dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", NULL);

//开启新线程,串行执行任务
NSLog(@"异步函数执行串行队列,当前线程:%@",[NSThread currentThread]);
dispatch_async(serialQueue, ^{
    NSLog(@"任务1:%@",[NSThread currentThread]);
});

dispatch_async(serialQueue, ^{
    NSLog(@"任务2:%@",[NSThread currentThread]);
});

dispatch_async(serialQueue, ^{
    NSLog(@"任务3:%@",[NSThread currentThread]);
});
//不开启新线程,串行执行任务
NSLog(@"同步函数执行串行队列,当前线程:%@",[NSThread currentThread]);

dispatch_sync(serialQueue, ^{
    NSLog(@"任务1:%@",[NSThread currentThread]);
});

dispatch_sync(serialQueue, ^{
    NSLog(@"任务2:%@",[NSThread currentThread]);
});

dispatch_sync(serialQueue, ^{
    NSLog(@"任务3:%@",[NSThread currentThread]);
});
并发队列:
  • 多个任务并发执行(自动开启多个线程同时执行任务)
  • 并发功能只有在异步(dispatch_async)函数下才有效!
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

//异步函数,并发队列
//开启新线程,并发执行任务
NSLog(@"异步函数执行并发队列,当前线程:%@",[NSThread currentThread]);
dispatch_async(concurrentQueue, ^{
    NSLog(@"任务1:%@",[NSThread currentThread]);
});

dispatch_async(concurrentQueue, ^{
    NSLog(@"任务2:%@",[NSThread currentThread]);
});

dispatch_async(concurrentQueue, ^{
   NSLog(@"任务3:%@",[NSThread currentThread]);
});
队列组:

任务1,任务2同时执行,所有任务都执行成功后回到主线程,高效率

NSLog(@"队列组执行任务,当前线程:%@",[NSThread currentThread]);
//1.创建队列组 dispatch_group_create()
dispatch_group_t group = dispatch_group_create();

//2.开启任务
//开启任务1
//提交任务到队列组 dispatch_group_async()
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    for (int i = 0; i < 5; i++) {
        NSLog(@"任务1 :%@",[NSThread currentThread]);
    }
});

//开启任务2
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    for (int i = 0; i < 5; i++) {
        NSLog(@"任务2 :%@",[NSThread currentThread]);
    }
});

//所有任务执行完毕,回到主线程进行操作
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    NSLog(@"任务1,2执行完毕,回到主线程:%@",[NSThread currentThread]);
});

延时执行:

延迟一段时间把一项任务提交到队列中执行,返回之后就不能取消,常用来在主队列上延迟执行一项任务。

NSLog(@"当前线程 %@", [NSThread currentThread]);
//GCD延时调用(主线程)(主队列)
/**
 * 1.声明一个变量 afterTime 指定要延迟的时长
 * 2.等待 afterTime 给定的时长,再异步地添加一个 Block 到主线程。
 */
dispatch_time_t afterTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC));//1

dispatch_after(afterTime, dispatch_get_main_queue(), ^{//2
    NSLog(@"GCD延时调用(主线程):%@",[NSThread currentThread]);
});

//GCD延时调用(其他线程)(全局并发队列)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSLog(@"GCD延时调用(其他线程):%@",[NSThread currentThread]);
});
打印:
[15276:540462] 当前线程 <NSThread: 0x600000068680>{number = 1, name = main}
[15276:540462] GCD延时调用(主线程):<NSThread: 0x600000068680>{number = 1, name = main}
[15276:540521] GCD延时调用(其他线程):<NSThread: 0x60800007c940>{number = 4, name = (null)}

dispatch_once()

在整个程序运行中,代码会以线程安全的方式执行并且只执行一次

for (int i = 0 ; i < 99999; i++) {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"执行一次:%d",i);
    });
}

dispatch_barrier_async()

读者写者锁(栅栏函数)

使用:

    dispatch_queue_t queue = dispatch_queue_create("barrier", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
    NSLog(@"任务1:%@",[NSThread currentThread]);
});

dispatch_async(queue, ^{
    NSLog(@"任务2:%@",[NSThread currentThread]);
});

dispatch_barrier_async(queue, ^{
    NSLog(@"---barrier---:%@",[NSThread currentThread]);
});

dispatch_async(queue, ^{
    NSLog(@"任务3:%@",[NSThread currentThread]);
});

dispatch_async(queue, ^{
    NSLog(@"任务4:%@",[NSThread currentThread]);
});

解决多个网络请求全部发送后再进行操作的问题方案:

1.Dispatch Group

对多个异步任务的完成进行监控
代码中的注释:

  1. 创建一个新的 Dispatch Group,它相当于一个用来记录未完成任务的计数器。

注意:

    - (IBAction)requestForData:(id)sender
    {
        __block NSMutableDictionary *errDict = [NSMutableDictionary dictionaryWithCapacity:0];
        __block NSMutableDictionary *successDic = [NSMutableDictionary dictionaryWithCapacity:0];

        dispatch_group_t requestGroup = dispatch_group_create();//1
    
        for(NSInteger i=1 ; i<4 ;i++)
        {
            dispatch_group_enter(requestGroup);//2
            [self requestForDataWithIndex:i block:^(NSArray *dataArray, NSInteger index, BOOL isSuccess) {
                if (isSuccess) {
                    NSLog(@"第%ld个网络请求成功,返回参数是:%@",(long)index,dataArray);
                    [successDic setObject:dataArray forKey:[NSNumber numberWithInteger:index]];
                }else{
                    NSLog(@"第%ld个网络请求失败,返回参数是:%@",(long)index,dataArray);
                    [errDict setObject:dataArray forKey:[NSNumber numberWithInteger:index]];
                }
                dispatch_group_leave(requestGroup);//3
            }];
        }
        dispatch_group_notify(requestGroup, dispatch_get_main_queue(), ^{//4
            //请求完成,主线程操作
            NSLog(@"请求全部完成,成功数据:%@,失败数据:%@",successDic,errDict);
        });
    }
打印
2017-03-21 14:11:42.098 GCD-Demo[15276:540462] 发起第1个网络请求:<NSThread: 0x600000068680>{number = 1, name = main}
2017-03-21 14:11:42.098 GCD-Demo[15276:540462] 发起第2个网络请求:<NSThread: 0x600000068680>{number = 1, name = main}
2017-03-21 14:11:42.099 GCD-Demo[15276:540462] 发起第3个网络请求:<NSThread: 0x600000068680>{number = 1, name = main}
2017-03-21 14:11:43.190 GCD-Demo[15276:540462] 第1个网络请求成功,返回参数是:(
1
)
2017-03-21 14:11:43.599 GCD-Demo[15276:540462] 第3个网络请求成功,返回参数是:(
1
)
2017-03-21 14:11:44.599 GCD-Demo[15276:540462] 第2个网络请求失败,返回参数是:(
0
)
2017-03-21 14:11:44.599 GCD-Demo[15276:540462] 请求全部完成,成功数据:{
    3 =     (
        1
    );
    1 =     (
        1
    );
},失败数据:{
    2 =     (
        0
    );
}

2.dispatch_apply()

提交队列,适用于并发循环.

- (IBAction)requestForData_Dispatch_apply:(id)sender
{
/**
 dispatch_apply() 

 @param iterations 迭代的次数
 @param queue 指定任务运行的队列
 @param size_t Block
 */
//    dispatch_apply(size_t iterations, dispatch_queue_t  _Nonnull queue, ^(size_t) {})

    __block NSMutableDictionary *errDict = [NSMutableDictionary dictionaryWithCapacity:0];
    __block NSMutableDictionary *successDic = [NSMutableDictionary dictionaryWithCapacity:0];
    dispatch_group_t requestGroup = dispatch_group_create();
    dispatch_apply(3, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t i) {
        dispatch_group_enter(requestGroup);
        [self requestForDataWithIndex:i block:^(NSArray *dataArray, NSInteger index, BOOL isSuccess) {
            if (isSuccess) {
                NSLog(@"第%ld个网络请求成功,返回参数是:%@",(long)index,dataArray);
                [successDic setObject:dataArray forKey:[NSNumber numberWithInteger:index]];
            }
            else
            {
                NSLog(@"第%ld个网络请求失败,返回参数是:%@",(long)index,dataArray);
                [errDict setObject:dataArray forKey:[NSNumber numberWithInteger:index]];
            }
            dispatch_group_leave(requestGroup);
        }];
    });
    dispatch_group_notify(requestGroup, dispatch_get_main_queue(), ^{
        //请求完成,主线程操作
        NSLog(@"请求全部完成,成功数据:%@,失败数据:%@",successDic,errDict);
    })
}
打印
2017-03-21 14:15:36.897 GCD-Demo[15276:540462] 发起第0个网络请求:<NSThread: 0x600000068680>{number = 1, name = main}
2017-03-21 14:15:36.897 GCD-Demo[15276:540521] 发起第1个网络请求:<NSThread: 0x60800007c940>{number = 4, name = (null)}
2017-03-21 14:15:36.897 GCD-Demo[15276:612863] 发起第2个网络请求:<NSThread: 0x600000260400>{number = 5, name = (null)}
2017-03-21 14:15:37.993 GCD-Demo[15276:540462] 第1个网络请求成功,返回参数是:(
1
)
2017-03-21 14:15:38.897 GCD-Demo[15276:540462] 第0个网络请求成功,返回参数是:(
1
)
2017-03-21 14:15:39.398 GCD-Demo[15276:540462] 第2个网络请求失败,返回参数是:(
0
)
2017-03-21 14:15:39.398 GCD-Demo[15276:540462] 请求全部完成,成功数据:{
0 =     (
    1
);
1 =     (
    1
);
},失败数据:{
2 =     (
    0
);
}

3.Dispatch Semaphore 信号量

  1. 信号量为0时 会阻塞线程,一直等待

信号量的理解:

- (IBAction)requestForData_Dispatch_semaphore_t:(id)sender
{   
    __block NSMutableDictionary *errDict = [NSMutableDictionary dictionaryWithCapacity:0];
    __block NSMutableDictionary *successDic = [NSMutableDictionary dictionaryWithCapacity:0];

    //创建一个信号量。参数指定信号量的起始值(必须大于0)
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(2);
    for (NSInteger i=0; i<4; i++) {
    
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//信号量-1
            [self requestForDataWithIndex:i block:^(NSArray *dataArray, NSInteger index, BOOL isSuccess) {
                if (isSuccess) {
                    NSLog(@"第%ld个网络请求成功,返回参数是:%@",(long)index,dataArray);
                    [successDic setObject:dataArray forKey:[NSNumber numberWithInteger:index]];
                }
                else
                {
                    NSLog(@"第%ld个网络请求失败,返回参数是:%@",(long)index,dataArray);
                    [errDict setObject:dataArray forKey:[NSNumber numberWithInteger:index]];
                }
                dispatch_semaphore_signal(semaphore);//信号量+1
            }];
        
        });
    }
}
打印:

这里我代码中设置信号量的起始值为2 ,就会同时发起0和1两个任务.0任务耗时长,1任务先返回后立即发起了任务2,0任务结束后立即发起了任务3.

2017-03-21 14:18:11.150 GCD-Demo[15276:613982] 发起第0个网络请求:<NSThread: 0x60800007fe80>{number = 6, name = (null)}
2017-03-21 14:18:11.150 GCD-Demo[15276:612860] 发起第1个网络请求:<NSThread: 0x608000064280>{number = 7, name = (null)}
2017-03-21 14:18:12.249 GCD-Demo[15276:540462] 第1个网络请求成功,返回参数是:(
1
)
2017-03-21 14:18:12.249 GCD-Demo[15276:613984] 发起第2个网络请求:<NSThread: 0x600000078880>{number = 8, name = (null)}
2017-03-21 14:18:13.151 GCD-Demo[15276:540462] 第0个网络请求成功,返回参数是:(
1
)
2017-03-21 14:18:13.151 GCD-Demo[15276:613985] 发起第3个网络请求:<NSThread: 0x600000077380>{number = 9, name = (null)}
2017-03-21 14:18:14.652 GCD-Demo[15276:540462] 第3个网络请求成功,返回参数是:(
1
)
2017-03-21 14:18:14.749 GCD-Demo[15276:540462] 第2个网络请求失败,返回参数是:(
0
)
  • 注: 这里只是为了理解信号量而提供的一种思路...看看就好,不要抬杠...

最后,附上我用来模拟网络请求的代码:

//模拟网络请求
- (void)requestForDataWithIndex:(NSInteger)index block:(Complete)callback
{
    NSLog(@"发起第%ld个网络请求:%@",(long)index,[NSThread currentThread]);
    NSArray * successArray = [NSArray arrayWithObjects:@1, nil];
    NSArray * failureArray = [NSArray arrayWithObjects:@0, nil];
    if (index == 0) {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            if (callback) {
                callback(successArray,index,YES);
            }
        });
    }
    else if (index == 1) {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            if (callback) {
                callback(successArray,index,YES);
            }
        });
    }
    else if (index == 2)
    {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            if (callback) {
                callback(failureArray,index,NO);
            }
        });
    }
    else if (index == 3)
    {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            if (callback) {
                callback(successArray,index,YES);
            }
        });
    }

}

另附上demo链接

Demo在这里下载...
路漫漫其修远兮...

上一篇 下一篇

猜你喜欢

热点阅读