9、延迟dispatch_after
dispatch_time_t timer = dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC);
dispatch_after(timer, dispatch_get_main_queue(), ^{
[self doSomething]
});
10、一次性执行dispatch_once
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
// some one-time task
});
在当前线程上执行
- 原理:
判断静态全局变量的值,默认是0,如果执行完成后,设置为-1
once内部会判断变量的值,如果是0,才执行 - dispatch_once 本身就是线程安全的。
单例
+(instancetype)sharedTools{
static NetworkTools *tools;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
});
return tools;
}
11、调度组dispatch_group
场景:
下载3首歌曲,全部下载完成之后,回到主线程程通知用户
// 1、创建调度组:
dispatch_group_t group = dispatch_group_create();
// 2、创建并发任务:
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_async(group, queue, ^{
NSLog(@"正在下载歌曲1");
});
dispatch_group_async(group, queue, ^{
NSLog(@"正在下载歌曲2");
});
dispatch_group_async(group, queue, ^{
NSLog(@"正在下载歌曲3");
});
// 3、接收通知:
// 当group中所有操作执行完成后发出通知
dispatch_group_notify(group, queue, ^{
NSLog(@"全部下载完成%@", [NSThread currentThread]);
});
2021-09-13 20:12:19.255006+0800 OCStudy[44177:948448] 正在下载歌曲1
2021-09-13 20:12:19.255115+0800 OCStudy[44177:950228] 正在下载歌曲3
2021-09-13 20:12:19.255010+0800 OCStudy[44177:950227] 正在下载歌曲2
2021-09-13 20:12:19.255718+0800 OCStudy[44177:950227] 全部下载完成<NSThread: 0x600002d58640>{number = 7, name = (null)}
- 原理
//GCD调度组原理方法
//创建调度组和队列
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create("YuanLi", DISPATCH_QUEUE_CONCURRENT);
//任务1
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"任务1");
dispatch_group_leave(group);
});
//任务2
dispatch_group_enter(group);
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@"任务2");
dispatch_group_leave(group);
});
//任务3
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"任务3");
dispatch_group_leave(group);
});
//任务全部执行完毕
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"任务执行完毕, 刷新UI");
});
//等待上面代码执行完毕后在执行下面的代码, 参数2:等待超时时间
//dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"Hello");
}
三、NSOperation
1、是什么?
NSOperation是对GCD的封装,面向对象,比GCD更易于使用。
2、优点
可添加完成的代码块,添加操作之间的依赖,方便控制之下顺序,可以设定优先级,可使用kvo观察操作执行状态。
NSOperation是一个抽象类,不能直接使用,有2个抽象类NSInvocationOperation,NSBlockOperation
3、NSInvocationOperation
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
queue.maxConcurrentOperationCount = 2;
NSBlockOperation *bo = [NSBlockOperation blockOperationWithBlock:^{
for (int i = 0; i<5; i++) {
NSLog(@"第%d次 执行任务 %@",i+1,[NSThread currentThread]);
}
}];
[bo addExecutionBlock:^{
for (int i = 0; i<5; i++) {
NSLog(@"第%d次 执行额外任务 %@",i+1,[NSThread currentThread]);
}
}];
[queue addOperation:bo];
[queue addOperationWithBlock:^{
}];
// 从输出结果可以看出来一些东西
// 1.任务并不是先执行任务后执行额外任务,而是相互穿插。
// 2.虽然跟理想中的结果不太一样,但是不论任务跟额外任务,却按照12345的顺序,老老实实的执行。
// 这里 maxConcurrentOperationCount 控制的不是并发线程的数量,而是一个队列中同时能并发执行任务的最大数。而且一个任务也并非只能在一个线程中运行。
4、NSBlockOperation
//在操作没有添加到队列中,操作直接start,任务是在主线程上执行,没有开启线程
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"这是NSBlockOperation执行的任务 %@",[NSThread currentThread]);
}];
// [blockOperation start];
//给block多加几个任务
// 给操作添加额外任务,并不会让这些任务按顺序执行。
// 但是初始化的任务仍然在主线程执行,另外两个任务分别创建了线程。 所以NSBlockOperation是否创建线程,取决于当前需要执行的任务数。
[blockOperation addExecutionBlock:^{
NSLog(@"Block任务1 %@",[NSThread currentThread]);
}];
[blockOperation addExecutionBlock:^{
NSLog(@"Block任务2 %@",[NSThread currentThread]);
}];
[blockOperation start];
// 总结一下
// 1.NSBlockOperation是否创建线程,取决于当前需要执行的任务数。
// 2.blockOperationWithBlock里面的任务,不一定在主线程执行。
5、优先级
操作优先级:没有什么意义 ,还是会交叉执行,达不到理想效果
6、操作依赖
//设置操作依赖来保证执行顺序
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
for (int i = 0; i<5; i++) {
NSLog(@"op1 %d",i);
}
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
for (int i = 0; i<5; i++) {
NSLog(@"op2 %d",i);
}
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
for (int i = 0; i<5; i++) {
NSLog(@"op3 %d",i);
}
}];
[op2 addDependency:op1];
[op3 addDependency:op2];
[queue addOperations:@[op1,op2,op3] waitUntilFinished:NO];
7、控制最大并发数(实现同步)
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
queue.maxConcurrentOperationCount = 1;
NSBlockOperation *bo = [NSBlockOperation blockOperationWithBlock:^{
for (int i = 0; i<5; i++) {
NSLog(@"第%d次 执行任务 %@",i+1,[NSThread currentThread]);
}
}];
[bo addExecutionBlock:^{
for (int i = 0; i<5; i++) {
NSLog(@"第%d次 执行额外任务 %@",i+1,[NSThread currentThread]);
}
}];
[queue addOperation:bo];
[queue addOperationWithBlock:^{
}];
// 从输出结果可以看出来一些东西
// 1.任务并不是先执行任务后执行额外任务,而是相互穿插。
// 2.虽然跟理想中的结果不太一样,但是不论任务跟额外任务,却按照12345的顺序,老老实实的执行。
// 这里 maxConcurrentOperationCount 控制的不是并发线程的数量,而是一个队列中同时能并发执行任务的最大数。而且一个任务也并非只能在一个线程中运行。
网友评论