GCD编程
今天谈论gcd编程的相关知识,gcd编程应该包涵的知识点有:g c d串行队列和并发队列,g c d的延时,线程组,信号量和定时器
gcd串行队列和并发队列
串行队列一次只执行一个线程,按照添加到队列的顺序依次执行。并发队列一次可以执行多个线程,线程的执行没有先后顺序。
注意:ui界面所在的线程队列为串行队列,
可以把gcd队列,gcd线程组,g c d信号源和gcd定时器封装成oc对象的形式。
首先如何理解串行队列
//串行队列
-(void)serailqueue{
GCDQueue *queue = [[GCDQueue alloc] initSerial];
//执行队列
[queue execute:^{
NSLog(@"1");
}];
//执行队列
[queue execute:^{
NSLog(@"2");
}];
//执行队列
[queue execute:^{
NSLog(@"3");
}];
//执行队列
[queue execute:^{
NSLog(@"4");
}];
//执行队列
[queue execute:^{
NSLog(@"5");
}];
//执行队列
[queue execute:^{
NSLog(@"6");
}];
}
结果表明它是按照顺序执行队列中的线程,输出结果为:1 2 3 4 5 6
如何理解并发队列
//并发队列
-(void)intconcurrent{
GCDQueue *queue = [[GCDQueue alloc] initConcurrent];
//执行队列
[queue execute:^{
NSLog(@"1");
}];
//执行队列
[queue execute:^{
NSLog(@"2");
}];
//执行队列
[queue execute:^{
NSLog(@"3");
}];
//执行队列
[queue execute:^{
NSLog(@"4");
}];
//执行队列
[queue execute:^{
NSLog(@"5");
}];
//执行队列
[queue execute:^{
NSLog(@"6");
}];
}
输出结果为:
2016-11-23 14:32:08.107 GCD[7877:288289] 2
2016-11-23 14:32:08.107 GCD[7877:288354] 3
2016-11-23 14:32:08.107 GCD[7877:288290] 1
2016-11-23 14:32:08.107 GCD[7877:288292] 4
2016-11-23 14:32:08.107 GCD[7877:288369] 5
2016-11-23 14:32:08.107 GCD[7877:288289] 6
线程的执行顺序是无法预测的
如何理解ui界面线程所在的队列是串行队列
一般情况下,我们会创建一个默认的线程,用一个下载图片的例子说明
//初始化imageview
self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
self.imageView.center = self.view.center;
[self.view addSubview:self.imageView];
[GCDQueue executeInGlobalQueue:^{
//处理业务逻辑
NSString *netURLString = @"";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:netURLString]];
//发起一个同步请求,会阻塞主线程
NSData *picdata = [NSURLConnection sendSynchronousRequest:request
returningResponse:nil
error:nil];
self.image = [UIImage imageWithData:picdata];
[GCDQueue executeInMainQueue:^{
//更新ui
self.imageView.image = self.image;
}];
}];
GCD延时执行
应该知道nsthread应该也有延时执行的操作,那gcd的延时执行有怎样的优点和缺点
当需要一个等待2s钟的操作,
nsthread的方式:
//nsthread方式的延时执行操作
[self performSelector:@selector(threadevent:)
withObject:self
afterDelay:2.f];
GCD的方式:
[GCDQueue executeInMainQueue:^{
NSLog(@"gcd线程事件");
}
afterDelaySecs:2.f];
gcd延时的优点:
1.它可以不用在单独写一个方法执行,写法简单。
gcd的缺点:它不可以取消延时操作,而nsthread可以通过[NSObject cancelPreviousPerformRequestsWithTarget:self];
取消延时的操作
GCD线程组
接着谈论gcd线程组有什么用处,在线程组中如何进行事件的监听
如果要实现一个等待线程一和线程2执行完毕后,在去执行线程3.用线程组怎样操作
//初始化一个线程组合
GCDGroup *group = [[GCDGroup alloc] init];
//创建一个线程队列
GCDQueue *queue = [[GCDQueue alloc] initConcurrent];
//让线程在group中执行(线程1)
[queue execute:^{
sleep(1);
NSLog(@"线程1执行完毕");
} inGroup:group];
//让线程在group中执行(线程2)
[queue execute:^{
sleep(3);
NSLog(@"线程2执行完毕");
} inGroup:group];
//监听线程组是否执行结束,然后执行线程3
[queue notify:^{
NSLog(@"线程3执行完毕");
} inGroup:group];
GCD定时器
怎样构建一个gcd定时器,它和nstimer创建的定时器有什么区别
首先,创建一个gcd定时器:
//运行gcdtimer
-(void)runGCDTimer{
//初始化定时器
self.gcdTimer = [[GCDTimer alloc] initInQueue:[GCDQueue mainQueue]];
//指定时间间隔以及要执行的事件
[self.gcdTimer event:^{
NSLog(@"gcd定时器");
} timeInterval:NSEC_PER_SEC];
//运行gcd定时器
[self.gcdTimer start];
}
//运行nastier
//运行nstimer定时器
-(void)runnstimer{
self.normaltimer = [NSTimer scheduledTimerWithTimeInterval:1.f
target:self
selector:@selector(timeevent)
userInfo:nil
repeats:YES];
}
-(void)timeevent{
NSLog(@"nstimer定时器");
}
gcd定时器和nstimer有什么区别:
nastier是作用在当前的runloop里的,如果把nastier用在table中会出现一些奇怪的现象,gcd定时器就不会出现这种情况。
GCD信号量
如何将gcd信号量的使用,以及将异步线程转为同步线程。
首先模拟一种场景,线程1执行完毕之后,然后用线程2执行。
思路:在线程1执行完毕后发送信号,线程2中等待接受信号。
//创建信号量
GCDSemaphore *semaphore = [[GCDSemaphore alloc] init];
//线程1 - 异步
[GCDQueue executeInGlobalQueue:^{
NSLog(@"线程1");
//发送信号
[semaphore signal];
}];
//线程2 - 异步
[GCDQueue executeInGlobalQueue:^{
NSLog(@"线程2");
//等待信号
[semaphore wait];
}];
GCD综合使用
就做一个使用gcd并发下载多张图片
self.view1 = [self creatImageViewWithFrame:CGRectMake(0, 0, 100, 100)];
self.view2 = [self creatImageViewWithFrame:CGRectMake(0, 100, 100, 100)];
self.view3 = [self creatImageViewWithFrame:CGRectMake(0, 200, 100, 100)];
NSString *net1 = @"";
NSString *net2 = @"";
NSString *net3 = @"";
[GCDQueue executeInGlobalQueue:^{
//获取图片
UIImage *image1 = [self accessdatabynetstring:net1];
[GCDQueue executeInMainQueue:^{
[UIView animateWithDuration:2.f animations:^{
self.view1.image = image1;
self.view1.alpha = 1.0;
} completion:^(BOOL finished) {
}];
}];
}];
[GCDQueue executeInGlobalQueue:^{
//获取图片
UIImage *image2 = [self accessdatabynetstring:net2];
[GCDQueue executeInMainQueue:^{
[UIView animateWithDuration:2.f animations:^{
self.view2.image = image2;
self.view2.alpha = 1.0;
} completion:^(BOOL finished) {
}];
}];
}];
[GCDQueue executeInGlobalQueue:^{
//获取图片
UIImage *image3 = [self accessdatabynetstring:net3];
[GCDQueue executeInMainQueue:^{
[UIView animateWithDuration:2.f animations:^{
self.view3.image = image3;
self.view3.alpha = 1.0;
} completion:^(BOOL finished) {
}];
}];
}];
截下来做一个顺序显示的图片,借助信号量。
思路:第一张图片加载完之后发一个信号,第二张完成之后在发一个信号,分别在2,3张图片加载时阻塞信号。
self.view1 = [self creatImageViewWithFrame:CGRectMake(0, 0, 100, 100)];
self.view2 = [self creatImageViewWithFrame:CGRectMake(0, 100, 100, 100)];
self.view3 = [self creatImageViewWithFrame:CGRectMake(0, 200, 100, 100)];
NSString *net1 = @"";
NSString *net2 = @"";
NSString *net3 = @"";
//初始化信号量
GCDSemaphore *semaphore = [[GCDSemaphore alloc] init];
[GCDQueue executeInGlobalQueue:^{
//获取图片
UIImage *image1 = [self accessdatabynetstring:net1];
[GCDQueue executeInMainQueue:^{
[UIView animateWithDuration:2.f animations:^{
self.view1.image = image1;
self.view1.alpha = 1.0;
} completion:^(BOOL finished) {
//发送信号
[semaphore signal];
}];
}];
}];
[GCDQueue executeInGlobalQueue:^{
//获取图片
UIImage *image2 = [self accessdatabynetstring:net2];
//阻塞
[semaphore wait];
[GCDQueue executeInMainQueue:^{
[UIView animateWithDuration:2.f animations:^{
self.view2.image = image2;
self.view2.alpha = 1.0;
} completion:^(BOOL finished) {
//发送信号
[semaphore signal];
}];
}];
}];
[GCDQueue executeInGlobalQueue:^{
//阻塞
[semaphore wait];
//获取图片
UIImage *image3 = [self accessdatabynetstring:net3];
[GCDQueue executeInMainQueue:^{
[UIView animateWithDuration:2.f animations:^{
self.view3.image = image3;
self.view3.alpha = 1.0;
} completion:^(BOOL finished) {
}];
}];
}];
}