iOS多线程基础(二)

简介

上一篇已经介绍了iOS中的多线程基本原理和NSThread的基本使用,接下来我们简单介绍第二种开启线程的方式GCD,在了解GCD之前我们首先了解同步函数、异步函数、串行队列、并发队列

基本概念

GCD:它的全称是Grand Central Dispatch ,强大的中枢调度器。
同步函数:同步指的是只能在当前线程中执行任务,不具备开启新线程的能力。
异步函数:异步指的是可以在新的线程中执行任务,具备开始新线程的能力。
并发队列:并发队列指的是可以让多个任务并发(同时)执行,自动开启多个线程同时执行任务。
串行队列:串行队列指的是让任务一个接一个的执行,一个任务执行完毕才继续执行下一个。只要是带串的你们就可以联想成糖葫芦。

任务和队列结合,对应的组合特点
  • 同步函数 + 主队列 (不用解释了肯定在主线程中执行)
        // 1.获得主队列
         dispatch_queue_t queue = dispatch_get_main_queue();
         // 2.将任务加入队列
         dispatch_sync(queue, ^{
             NSLog(@"1-----%@", [NSThread currentThread]);
         });
         dispatch_sync(queue, ^{
             NSLog(@"2-----%@", [NSThread currentThread]);
         });
         dispatch_sync(queue, ^{
             NSLog(@"3-----%@", [NSThread currentThread]);
         });
    
  • 异步函数 + 主队列:只在主线程中执行任务
     // 1.获得主队列
     dispatch_queue_t queue = dispatch_get_main_queue();
    // 2.将任务加入队列
    dispatch_async(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });
    
  • 同步函数 + 串行队列:不会开启新的线程,在当前线程执行任务。任务是串行的,执行完一个任务,再执行下一个任务
         // 1.创建串行队列
        dispatch_queue_t queue = dispatch_queue_create("ai.bobo.queue", DISPATCH_QUEUE_SERIAL);
        // 2.将任务加入队列
        dispatch_sync(queue, ^{
            NSLog(@"1-----%@", [NSThread currentThread]);
        });
        dispatch_sync(queue, ^{
            NSLog(@"2-----%@", [NSThread currentThread]);
        });
        dispatch_sync(queue, ^{
            NSLog(@"3-----%@", [NSThread currentThread]);
        });
    
  • 同步函数 + 并发队列:不会开启新的线程
          dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        // 2.将任务加入队列
        dispatch_sync(queue, ^{
            NSLog(@"1-----%@", [NSThread currentThread]);
        });
        dispatch_sync(queue, ^{
            NSLog(@"2-----%@", [NSThread currentThread]);
        });
        dispatch_sync(queue, ^{
            NSLog(@"3-----%@", [NSThread currentThread]);
        });
    
  • 异步函数 + 并发队列:可以同时开启多条线程
     	   // 1.获得全局的并发队列
     	    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     	    
     	    // 2.将任务加入队列
     	    dispatch_async(queue, ^{
     	        for (NSInteger i = 0; i<10; i++) {
     	            NSLog(@"1-----%@", [NSThread currentThread]);
     	        }
     	    });
     	    dispatch_async(queue, ^{
     	        for (NSInteger i = 0; i<10; i++) {
     	            NSLog(@"2-----%@", [NSThread currentThread]);
     	        }
     	    });
     	    dispatch_async(queue, ^{
     	        for (NSInteger i = 0; i<10; i++) {
     	            NSLog(@"3-----%@", [NSThread currentThread]);
     	        }
     	    });
    
GCD线程中的通信

我们在开发中使用GCD 开启一条子线程执行耗时操作,然后子线程任务执行完之后获取到对应的数据,我们将数据展示到手机页面上,这样涉及到操作UI页面,那么必须回到主线程中进行操作。 其实也很简单,只需要将队列设置dispatch_get_main_queue() 就可以了,代码如下,模拟一个加载网络图片的操作。

    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
           // 图片的网络路径
           NSURL *url = [NSURL URLWithString:@"https://i1.hdslb.com/bfs/face/5cb955002eab27132543f9d8c86e8f3beac2ab4c.jpg"];
           // 加载图片
           NSData *data = [NSData dataWithContentsOfURL:url];
           // 生成图片
           UIImage *image = [UIImage imageWithData:data];
           // 回到主线程
           dispatch_async(dispatch_get_main_queue(), ^{
               self.imageView.image = image;
           });
       });
   }
dispatch_barrier_async 栅栏的使用

在开发中我可能开启多个线程,但是有时候我在其中的一个线程中要用到其中一个线程中的数据,无法确认他们执行的顺序,苹果提供了dispatch_barrier_async这个函数,栅栏就是阻挡的意思,比较形象,就是在栅栏前的先执行,前面执行完了之后在执行栅栏函数和之后的任务。例如异步函数中有三条线程,线程3必须在线程1、2执行完成之后才执行,我们就可以使用栅栏挡一下。代码如下

	- (void)barrier
	{
	    dispatch_queue_t queue = dispatch_queue_create("aibobo", 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]);
	    });
	}
GCD中的延迟执行与执行一次的函数
 - (void)delay
  {   
      //dispatch_after方法 2.0 * NSEC_PER_SEC代表2秒之后执行
          dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
              NSLog(@"run-----");
          });
     
    //还有其他方法实现:除了前面NSThread的睡的方法
    //2秒之后在执行
          [self performSelector:@selector(run) withObject:nil afterDelay:2.0];
         //定时器也可以实现
      [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:NO];
  }
  //dispatch_once只执行一次,开发者常用于单例模式的设计中
  - (void)once
  {
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
          NSLog(@"------run");
      });
}
dispatch_group_async线程组,这个在开发中用的也比较多,用法的场景和dispatch_barrier_async一样,下面举例一个合成图片
	- (void)group
	{
	    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
	    // 创建一个队列组
	    dispatch_group_t group = dispatch_group_create();
	    // 1.下载图片1
	    dispatch_group_async(group, queue, ^{
	        // 图片的网络路径
	        NSURL *url = [NSURL URLWithString:@"网络图片1"];
	        // 加载图片
	        NSData *data = [NSData dataWithContentsOfURL:url];
	        
	        // 生成图片
	        self.image1 = [UIImage imageWithData:data];
	    });
	    
	    // 2.下载图片2
	    dispatch_group_async(group, queue, ^{
	        // 图片的网络路径
	        NSURL *url = [NSURL URLWithString:@"网络图片2"];
	        // 加载图片
	        NSData *data = [NSData dataWithContentsOfURL:url];
	        // 生成图片
	        self.image2 = [UIImage imageWithData:data];
	    });
	    // 3.将图片1、图片2合成一张新的图片
	    dispatch_group_notify(group, queue, ^{
	        // 开启新的图形上下文
	        UIGraphicsBeginImageContext(CGSizeMake(100, 100));
	        // 绘制图片
	        [self.image1 drawInRect:CGRectMake(0, 0, 50, 100)];
	        [self.image2 drawInRect:CGRectMake(50, 0, 50, 100)];
	        // 取得上下文中的图片
	        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
	        // 结束上下文
	        UIGraphicsEndImageContext();
	        // 回到主线程显示图片
	        dispatch_async(dispatch_get_main_queue(), ^{
	            // 4.将新图片显示出来 
	            self.imageView.image = image;
	        });
	    });
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值