@implementation ViewController
#pragma mark - 基本概念
//1.两个核心的概念
//任务:想要做的事情(需要执行的操作)
//队列:存放任务的容器(特点是先进先出)
//2.四大名词
//(1)任务的执行方式(决定了能不能开启新的线程)
//同步:任务在当前线程中执行(不具备开启新线程的能力)--- 任务需要马上执行
//异步:任务在其他线程中执行(具备开启新线程的能力)--- 任务可以等当前函数结束后再执行
//(2)队列的类型
//并发:多个任务可以同时执行(前提是有多个线程)
//串行:队列中任务按顺序一个一个执行;必须是一个执行完,再执行下一个
//3.使用步骤
//(1)创建队列
//(2)将指定的任务放到创建好的队列中。(将任务放到队列中后,GCD会自动将队列中的任务取出来放到线程中执行)
#pragma mark - UITouch
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self test9];
//[self test8];
//[self test7];
//[self test6];
//[self test5];
//[self test4];
//[self test3];
//[self test2];
//[self test1];
}
#pragma mark - 队列组
//用来存放队列的
//作用:多个任务在不同的线程中异步执行,全部执行完毕后回到主线程
- (void)test9{
//1.创建一个队列组(存放队列的)
dispatch_group_t group = dispatch_group_create();
//2.将任务添加到队列组的队列中
//参数1:队列组
//参数2:队列
//参数3:任务
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"1:%@", [NSThread currentThread]);
[self downloadImage:@"http://yuting.local/shareX/1092.jpg"];
NSLog(@"下载图片1");
});
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"2:%@", [NSThread currentThread]);
[self downloadImage:@"http://img5.duitang.com/uploads/item/201602/25/20160225131806_AC8BP.jpeg"];
NSLog(@"下载图片2");
});
//3.队列组中的所有任务执行完毕后才回到主线程
//参数1:哪个组的任务全部完成
//参数2:组的任务完成后执行哪个队列中的任务
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"回到了线程");
NSLog(@"%@", [NSThread currentThread]);
});
}
#pragma mark - !!!线程间通信
- (void)test8{
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"%@", [NSThread currentThread]);
UIImage * image = [self downloadImage:@""];
NSLog(@"%@", image);
//将图片传回主线程(将任务放到主队列中)
dispatch_async(dispatch_get_main_queue(), ^{
//在主队列中需要执行的任务
_imageView.image = image;
});
});
}
- (UIImage *)downloadImage:(NSString *)path{
//1.创建url
NSURL * url = [NSURL URLWithString:path];
NSData * data = [[NSData alloc] initWithContentsOfURL:url];
UIImage * image = [UIImage imageWithData:data];
//返回下载的图片
return image;
}
#pragma mark - 主队列
//主队列:主队列是系统创建好,专门用来存储在主线程中执行的任务的队列。添加到主队列中的任务,只能在主线程中执行的。使用的时候只需要直接去拿。
//注意:只能在主队列中异步执行任务
//主队列:在主线程中按顺序执行
//同步:不开新的线程
//结果:死锁
- (void)test7{
//1.拿到主队列
dispatch_queue_t queue = dispatch_get_main_queue();
NSLog(@"开始");
//2.将任务添加到主队列中,同步执行
for (int i = 0; i < 10; i++) {
dispatch_sync(queue, ^{
[self longTimeOperation:i];
});
}
NSLog(@"结束");
}
//主队列:在主线程中按顺序执行
//异步:在其他线程中执行(需要开启新的线程)
//结果:在主线程中按顺序一个一个执行
- (void)test6{
//1.拿到主队列
dispatch_queue_t queue = dispatch_get_main_queue();
//2.将任务添加到主队列中,异步执行
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
[self longTimeOperation:i];
});
}
}
#pragma mark - 全局队列
//全局队列:系统为我们已经创建好的一个并发队列,使用的时候只需要直接去拿
- (void)test5{
//1.拿到全局队列
//参数1:队列优先级, 0
//参数2:预留参数
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
//2.添加任务,异步执行
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
[self longTimeOperation:i];
});
}
}
#pragma mark - GCD的基本使用
//并发:可以多个任务同时执行
//异步:在其他线程中执行任务(可以开启新的线程)
//结果:多个任务在多个线程中同时执行(先“结束”,再执行任务)
- (void)test4{
//1.创建并发队列
dispatch_queue_t queue = dispatch_queue_create("bb", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"开始");
//2.将任务添加到队列中,异步执行
for (int i = 0; i < 10; i ++) {
dispatch_async(queue, ^{
[self longTimeOperation:i];
});
}
NSLog(@"结束");
}
//并发:多个任务同时执行
//同步:在当前线程中执行(不会开启新的线程)
//结果:所有任务在主线程中按顺序一个一个执行(先执行任务,再结束)
- (void)test3{
//1.创建并发队列
//DISPATCH_QUEUE_CONCURRENT 并发
dispatch_queue_t queue = dispatch_queue_create("aaa", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"开始");
//2.将任务添加到队列中,同步执行
for (int i = 0; i < 10; i++) {
dispatch_sync(queue, ^{
[self longTimeOperation:i];
});
}
NSLog(@"结束");
}
//串行:任务一个一个按顺序执行
//异步:在其他线程中执行(开启新的线程)
//结果:在子线程中,任务按顺序一个一个执行(先“结束”,再执行任务)
- (void)test2{
//1.创建串行队列
dispatch_queue_t queue = dispatch_queue_create("aaa", NULL);
NSLog(@"开始");
//2.将任务添加到队列中,异步执行
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
[self longTimeOperation:i];
});
}
NSLog(@"结束");
}
//串行:任务一个一个按顺序执行
//同步:在当前线程中执行(不开启新的线程)
//结果:在主线程中,任务按顺序一个一个执行(先执行任务然后再“结束”)
- (void)test1{
//1.创建串行队列
//dispatch_queue_t 队列类型
//参数1:队列的标签(队列名),可以传任意的C语言字符串
//参数2:队列属性,传入并发或者串行
//DISPATCH_QUEUE_SERIAL (NULL) 串行
//DISPATCH_QUEUE_CONCURRENT 并发
dispatch_queue_t queue = dispatch_queue_create("abc", DISPATCH_QUEUE_SERIAL);
//2.将一个任务添加到队列中(同步的)
//参数1:队列
//参数2:任务
// dispatch_sync(queue, ^{
//
// [self longTimeOperation:0];
//
// });
NSLog(@"开始");
//将多个任务添加到队列中
for (int i = 0; i < 10; i++) {
dispatch_sync(queue, ^{
[self longTimeOperation:i];
});
}
NSLog(@"结束");
}
#pragma mark - 任务
- (void)longTimeOperation:(int)i{
NSLog(@"%@:%d", [NSThread currentThread], i);
}
@end
使用GCD函数可以进行延时操作,该函数为:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[xxManager showMessage:message];
});
现在我们来分解一下参数:
dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(delayInSeconds * NSEC_PER_SEC)) :
其中:
DISPATCH_TIME_NOW:从现在开始计时
(int64_t)(delayInSeconds:自定义参数(比如 2)与后面参数结合表示延时的时间长度
NSEC_PER_SEC:在头文件中的定义如下:
(#define NSEC_PER_SEC 1000000000ull) /* nanoseconds per second */ 该参数表示从现在开始经过多少纳秒 dispatch_get_main_queue():表示主队列 ^{ }:表示一个block任务。
现在来测试一下经过多少纳秒之后,由主队列调度任务是异步执行还是同步执行,代码如下:
// when 时间 从现在开始经过多少纳秒
dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC));
void (^task)() = ^ {
// 延迟操作执行的代码
NSLog(@"%@", [NSThread currentThread]);
};
// 经过多少纳秒,由主队列调度任务异步执行
dispatch_after(when, dispatch_get_main_queue(), task);
// 先执行就是异步,后执行就是同步
NSLog(@"come here");
延时操作 执行的是异步操作。
GCD中有个函数能够保证某段代码在程序运行过程中只被执行1次!该函数如下:
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//写入代码块
})
dispatch_once_t在头文件中得定义如下:
typedef long dispatch_once_t 由此可知该类型是个long类型。当onceToken等于0时就会执行block代码。
dispatch_once 是线程安全的,只要涉及到线程安全就会涉及到锁,dispatch_once内部也有一把锁,性能比互斥锁高!
利用该函数我们可以来写一个单例模式 单例模式可以保证在程序运行过程,一个类只有一个实例且该实例易于供外界访问,从而方便控制实例个数,并节约系统资源,当应用程序需要共享一份资源时就可以用单例模式来实现
+(instancetype)shareDataBaseManager{
static DataBaseManager *manager;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (!manager) {
manager = [[DataBaseManager alloc]initPrivate];
}
});
return manager;
}