xml地图|网站地图|网站标签 [设为首页] [加入收藏]

的常用函数

来源:http://www.ccidsi.com 作者:呼叫中心培训课程 人气:195 发布时间:2020-05-05
摘要:至于 iOS 四线程中 GCD的底蕴知识已在上一篇小说中详尽表达,请参见《轻巧学iOS八线程之 GCD的骨干接受》进行问询,本文首要对 GCD 中的二种常用函数做越来越概述。 一、什么是GCD?

至于 iOS 四线程中 GCD 的底蕴知识已在上一篇小说中详尽表达,请参见《轻巧学iOS八线程之 GCD 的骨干接受》进行问询,本文首要对 GCD 中的二种常用函数做越来越概述。

一、什么是GCD?

在介绍GCD使用在此之前,大家先来介绍一下什么样是GCD,假如大家都不亮堂GCD是怎样就毫无谈GCD的选取了 ,废话十分的少说,首先大家来介绍第三个点,这就是何等是GCD?,GCD的齐全部都以Grand Central Dispatch,经常它被译为“牛逼的灵魂调整器”,见到这一个牛逼的称谓是还是不是深感高大上 就如刚开始大家接触计算机的时候一听到CPU就想开中心微处理器,感觉好像相当酷呆了的事物,但是大家潜移默化了之后.....其实确实是非常酷炸了的事物(开个玩笑哈..)
GCD是纯C语言的东西,它提供了丰裕多强大的函数,下边小编会挨个的为大家介绍

一、简介
1、什么是GCD?

在 GCD 中的常用函数重要有栅栏函数、一遍性函数、延迟施行函数、飞快迭代函数,最后富含 队列组的使用以及线程间的通信

GCD中有2个主旨概念:职责、队列

--- 1.职分:实践什么样操作
--- 2.队列:用来贮存任务

有备无患是Grand CentralDispatch,可译为“伟大的中枢调解器”

栅栏函数的作用是用来调整职分的施行各类,必得上边的职分 1 执行完结才施行当前栅栏职分,必妥善前栅栏义务施行完结才施行上边包车型客车职务 2。

--- 队列的种类:并发队列 与 串行队列

将职责加多到行列中,GCD会自行将队列中的任务抽取,放到对应的线程中试行,任务的抽取遵守队列的 FIFO原则:先进先出,后进后出

纯C语言,提供了不菲强大的函数

//1.获取并发队列 dispatch_queue_t queue = dispatch_queue_create("barrier", DISPATCH_QUEUE_CONCURRENT); //2.异步函数dispatch_async(queue, ^{ NSLog(@"1 --- %@", [NSThread currentThread]);}); //3.设置栅栏dispatch_barrier_async(queue, ^{ NSLog(@"                ");});dispatch_async(queue, ^{ NSLog(@"2 --- %@", [NSThread currentThread]);});

二、实行任务:同步、异步、栅栏

同步 dispatch_sync : 只能在当下线程中实践职责,不富有开启新线程的本事

 dispatch_sync(dispatch_queue_tqueue, dispatch_block_block)

注意:
接受sync函数往当前串行队列中增进职责,会卡住当前的串行队列
异步 dispatch_async:能够在新的线程中试行职分,具有开启新线程的力量

dispatch_`async`(dispatch_queue_tqueue, dispatch_block_block)

除此以外二个推行任务的不二秘籍:dispatch_barrier_async 栅栏
此情此景:在前边的职分实行完结后它才实行,何况它背后的职务等它奉行到位未来才会实行
在乎:那些queue不可能是全局的产出队列

dispatch_barrier_async(dispatch_queue_tqueue, dispatch_block_block)

2、GCD的优势

注意:栅栏函数不能使用全局并发队列,会丧失拦截功能

三、队列:串行 与 并行

使用dispatch_queue_create函数创制队列

dispatch_queue_t dispatch_queue_create(
   const char *label, //队列名称 
   dispatch_queue_attr_t  attr //队列的类型
)

1、并发队列:(ConcurrentDispatch Queue)
能够让多少个职务并发(同期)实施(自动开启多个线程同有时间施行职务)
注意:并发功效唯有在异步(dispatch_async)函数下才使得,因为异步函数才享有开启新线程的力量,而一同函数只能在这个时候此刻线程中实施不抱有开启线程的力量。
并发队列获取

手动制造并发队列 dispatch_queue_create

dispatch_queue_t queue = dispatch_queue_create("队列名称", DISPATCH_QUEUE_CONCURRENT)

GCD默许已经提供了全局的出现队列,供整个应用使用,能够不用手动创制,使用dispatch_get_global_queue函数取得全局的面世队列

// 取得全局并发队列

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

2、串行队列:(SerialDispatch Queue)
让职务八个随后三个地履行(一个职务实施实现后,再奉行下三个任务)
注意:
利用sync函数往当前串行队列中增多任务,会卡住当前的串行队列
GCD中获得串行有2种路子

串行队列创立

使用dispatch_queue_create函数

//创建串行队列(队列类型传递NULL或者DISPATCH_QUEUE_SERIAL)
dispatch_queue_tqueue = dispatch_queue_create("队列名称",NULL)

主队列(是GCD自带的一种奇特的串行队列)

位居主队列中的职责,都会安放主线程中实施

dispatch_queue_tqueue = dispatch_get_main_queue();

3、同步 / 异步 与 并发 / 串行 怎样区分
同台和异步首要影响:能不能够打开新的线程

一齐:只是在脚下线程中奉行职责,不持有开启新线程的力量
异步:能够在新的线程中举办职责,具备开启新线程的本事
现身和串行首要影响:职务的推行办法

出现:允许四个义务并发(同时)实行
串行:贰个任务执行完结后,再执行下四个任务

GCD是苹果集团为多核
的相互运算建议的消除方案
GCD会活动利用更加多的CPU内核(比如双核、四核)
GCD会活动管理线程的生命周期
(创建线程、调治职责、销毁线程),相比较NSThread要求手动管理线程注脚周期
只必要告诉GCD想要实行怎么着职责,无需编制任何线程管理代码

叁次性函数断章取义就是在程序的运转进度中,贰回性函数中的代码只会实施三回,一回性函数的内部原理正是开头时 onceToken == 0,假使为 0 则举行,试行之后值为 -1,就不执行了。贰次性函数在单例中会日常利用。

四、GCD基本选择

#import "ViewController.h"


@implementation ViewController

/*
 如果是在子线程中调用 同步函数   主队列, 那么没有任何问题
 */
- (void)syncMain2
{
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        // block会在子线程中执行
        //        NSLog(@"%@", [NSThread currentThread]);

        dispatch_queue_t queue = dispatch_get_main_queue();
        dispatch_sync(queue, ^{
            // block一定会在主线程执行
            NSLog(@"%@", [NSThread currentThread]);
        });
    });
    NSLog(@"------------");
}
/*
 如果是在主线程中调用同步函数   主队列, 那么会导致死锁
 导致死锁的原因:
 sync函数是在主线程中执行的, 并且会等待block执行完毕. 先调用
 block是添加到主队列的, 也需要在主线程中执行. 后调用
 */
- (void)syncMain
{
    NSLog(@"%@", [NSThread currentThread]);
    // 主队列:
    dispatch_queue_t queue = dispatch_get_main_queue();

    //  如果是调用 同步函数, 那么会等同步函数中的任务执行完毕, 才会执行后面的代码
    // 注意: 如果dispatch_sync方法是在主线程中调用的, 并且传入的队列是主队列, 那么会导致死锁
    dispatch_sync(queue, ^{
        NSLog(@"----------");
        NSLog(@"%@", [NSThread currentThread]);
    });
    NSLog(@"----------");
}
/*
 异步   主队列 : 不会创建新的线程, 并且任务是在主线程中执行
 */
- (void)asyncMain
{
    // 主队列:
    // 特点: 只要将任务添加到主队列中, 那么任务"一定"会在主线程中执行 
    无论你是调用同步函数还是异步函数
    dispatch_queue_t queue = dispatch_get_main_queue();

    dispatch_async(queue, ^{
        NSLog(@"%@", [NSThread currentThread]);
    });
}
/*
 同步   并发 : 不会开启新的线程
 妻管严
 */
- (void)syncConCurrent
{
    // 1.创建一个并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

    // 2.将任务添加到队列中
    dispatch_sync(queue, ^{
        NSLog(@"任务1  == %@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任务2  == %@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任务3  == %@", [NSThread currentThread]);
    });

     NSLog(@"---------");
}
/*
 同步   串行: 不会开启新的线程
 注意点: 如果是调用 同步函数, 那么会等同步函数中的任务执行完毕, 才会执行后面的代码
 */
- (void)syncSerial
{
    // 1.创建一个串行队列
    // #define DISPATCH_QUEUE_SERIAL NULL
    // 所以可以直接传NULL
    dispatch_queue_t queue = dispatch_queue_create("com.520it.lnj", NULL);

    // 2.将任务添加到队列中
    dispatch_sync(queue, ^{
        NSLog(@"任务1  == %@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任务2  == %@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任务3  == %@", [NSThread currentThread]);
    });

    NSLog(@"---------");
}
/*
 异步   串行:会开启新的线程
但是只会开启一个新的线程
 注意: 如果调用 异步函数, 那么不用等到函数中的任务执行完毕, 就会执行后面的代码
 */
- (void)asynSerial
{
    // 1.创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("com.520it.lnj", DISPATCH_QUEUE_SERIAL);
    /*
     能够创建新线程的原因:
     我们是使用"异步"函数调用
     只创建1个子线程的原因:
     我们的队列是串行队列
     */
    // 2.将任务添加到队列中
    dispatch_async(queue, ^{
        NSLog(@"任务1  == %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任务2  == %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任务3  == %@", [NSThread currentThread]);
    });

    NSLog(@"--------");
}

/*
 异步   并发 : 会开启新的线程
 如果任务比较多, 那么就会开启多个线程
 */
- (void)asynConcurrent
{
    /*
     执行任务
     dispatch_async
     dispatch_sync
     */

    /*
     第一个参数: 队列的名称
     第二个参数: 告诉系统需要创建一个并发队列还是串行队列
     DISPATCH_QUEUE_SERIAL :串行
     DISPATCH_QUEUE_CONCURRENT 并发
     */
    //    dispatch_queue_t queue = dispatch_queue_create("com.520it.lnj", DISPATCH_QUEUE_CONCURRENT);

    // 系统内部已经给我们提供好了一个现成的并发队列
    /*
     第一个参数: iOS8以前是优先级, iOS8以后是服务质量
     iOS8以前
     *  - DISPATCH_QUEUE_PRIORITY_HIGH          高优先级 2
     *  - DISPATCH_QUEUE_PRIORITY_DEFAULT:      默认的优先级 0
     *  - DISPATCH_QUEUE_PRIORITY_LOW:          低优先级 -2
     *  - DISPATCH_QUEUE_PRIORITY_BACKGROUND:

     iOS8以后
     *  - QOS_CLASS_USER_INTERACTIVE  0x21 用户交互(用户迫切想执行任务)
     *  - QOS_CLASS_USER_INITIATED    0x19 用户需要
     *  - QOS_CLASS_DEFAULT           0x15 默认
     *  - QOS_CLASS_UTILITY           0x11 工具(低优先级, 苹果推荐将耗时操作放到这种类型的队列中)
     *  - QOS_CLASS_BACKGROUND        0x09 后台
     *  - QOS_CLASS_UNSPECIFIED       0x00 没有设置

     第二个参数: 废物
     */
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

    /*
     第一个参数: 用于存放任务的队列
     第二个参数: 任务(block)

     GCD从队列中取出任务, 遵循FIFO原则 , 先进先出
     输出的结果和苹果所说的原则不符合的原因: CPU可能会先调度其它的线程

     能够创建新线程的原因:
     我们是使用"异步"函数调用
     能够创建多个子线程的原因:
     我们的队列是并发队列
     */
    dispatch_async(queue, ^{
        NSLog(@"任务1  == %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任务2  == %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任务3  == %@", [NSThread currentThread]);
    });
}
@end
线程间通信
#import "ViewController.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView;

@end

@implementation ViewController

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"--------");
    // 1.除主队列以外, 随便搞一个队列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

    // 2.调用异步函数
    dispatch_async(queue, ^{
        // 1.下载图片
        NSURL *url = [NSURL URLWithString:@"http://pic.4j4j.cn/upload/pic/20130531/07ed5ea485.jpg"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        // 2.将二进制转换为图片
        UIImage *image = [UIImage imageWithData:data];

        // 3.回到主线程更新UI
//        self.imageView.image = image;
        /*
         技巧:
         如果想等UI更新完毕再执行后面的代码, 那么使用同步函数
         如果不想等UI更新完毕就需要执行后面的代码, 那么使用异步函数
         */
        dispatch_sync(dispatch_get_main_queue(), ^{ // 会等block代码执行完毕后,执行后面最后一句的打印代码
            self.imageView.image = image;
        });
        NSLog(@"设置图片完毕 %@", image);
    });
}
@end

3、GCD中有2个中央概念:义务、队列

static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{ NSLog(@"只执行一次,默认是线程安全的");});

五、线程间通讯

从子线程回到主线程

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{

  // 1. 执行耗时的异步操作 
    .......

 //2. 回到主线程,执行UI刷新操作
  dispatch_async(dispatch_get_main_queue(),^{

 //这里使用的是dispatch_async:不用等block执行完,就会调用下面的打印代码,如果替换为使用dispatch_sync同步函数:那么会等block执行更新UI完毕,才会执行最后一句打印代码
      .......
  });
});
NSLog(@”更新UI界面结束”);

实例程序:子线程下载图片,回到主线程刷新UI分界面

#import "ViewController.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView;

@end

@implementation ViewController

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"--------");
    // 1.除主队列以外, 随便搞一个队列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

    // 2.调用异步函数
    dispatch_async(queue, ^{
        // 1.下载图片
        NSURL *url = [NSURL URLWithString:@"https://www.baidu.com/img/bd_logo1.png"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        // 2.将二进制转换为图片
        UIImage *image = [UIImage imageWithData:data];

        // 3.回到主线程更新UI
//        self.imageView.image = image;
        /*
         技巧:
         如果想等UI更新完毕再执行后面的代码, 那么使用同步函数
         如果不想等UI更新完毕就需要执行后面的代码, 那么使用异步函数
         */
        dispatch_sync(dispatch_get_main_queue(), ^{ // 会等block代码执行完毕后,执行后面最后一句的打印代码
            self.imageView.image = image;
        });
        NSLog(@"设置图片完毕 %@", image);
    });
}
@end

职分:实践什么样操作
队列:用来寄存职责队列的等级次序:并发队列 与 串行队列

注意:一次性函数不能放入懒加载中

六、延时推行

1、iOS管见所及的延时实践,调用NSObject的章程
performSelector 一旦定制好延时义务,不会堵塞当前线程
//2秒后再调用self的run方法

[self performSelector:@selector(run) withObject:nil afterDelay:2.0];

2、使用GCD函数

// 该方法中, 会遵照传入的队列来决定回掉block在哪个线程中实践
// 假设传入的是主队列, 那么block会在主线程调用
// 即使传入的是大局队列, 那么block会在子线程中调用

  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{ // 这里传入全局队列会在子线程中执行block,如果传入主队列就会在主线程中执行block
      NSLog(@"3秒之后执行  %@", [NSThread currentThread]);
  });

3、使用NSTimer

[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(test) userInfo:nil repeats:NO];

- (void)test{
    NSLog(@"---- begin-----");
    [NSThread sleepForTimeInterval:3]; // 它会卡住线程
    NSLog(@"---- end-----");
}
 [NSThread sleepForTimeInterval:3];

延时执行不要用 sleepForTimeInterval(它会卡住线程) ( 不使用 )
- (void)dely1{
  // 1、延时执行不要用 sleepForTimeInterval(它会卡住线程)
  NSLog(@"---- begin-----");
  [NSThread sleepForTimeInterval:3];
  NSLog(@"---- end-----");
}

将职务增多到行列中,GCD会自行将队列中的职务抽取,放到对应的线程中实施,职务的抽出遵守队列的 FIFO原则:先进先出
,后进后出

在既往的就学中,大家早已明白了三种完成延时推行的措施:

七、二回性代码

使用dispatch_once函数能有限援助某段代码在程序运营过程中只被奉行1次,只实行1次的代码(那其间默许是线程安全的卡塔尔(قطر‎
注意: 万万不能够把一次性代码充当懒加载来利用

// 注意: 万万不可能把贰遍性代码充任懒加载来利用

   static dispatch_once_t onceToken;
   dispatch_once(&onceToken, ^{
      NSLog(@" 一次性代码");
   });

皇家娱乐在线app 1

// 2秒后再调用self的run方法[self performSelector:@selector withObject:nil afterDelay:2.0];

// 2秒后再调用self的run方法[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector userInfo:nil repeats:NO];

八、快速迭代

使用dispatch_apply函数能展开高效迭代遍历,可是它和for循环又有个别不一致

第多少个参数: 要求遍历四回
其次个参数: 决定第八个参数的block在哪些线程中实践
其多少个参数: 回掉

dispatch_apply(10, 队列queue, ^(size_tindex){
  //执行10次代码,index顺序不确定
});

实例:拷贝文件到指标目录中 : 火速迭代完毕

// 1.定义变量记录原始文件夹和目标文件夹的路径
    NSString *sourcePath = @"/Users/cjp/Desktop/原始文件";
    NSString *destPath = @"/Users/cjp/Desktop/目标文件";
    // 2.取出原始文件夹中所有的文件
    NSFileManager *manager = [NSFileManager defaultManager];
    NSArray *files = [manager subpathsAtPath:sourcePath];
    //    NSLog(@"%@", files);
    // 3.开始拷贝文件
    /*
     for (NSString *fileName in files) {
     // 3.1生产原始文件的绝对路径
     NSString *sourceFilePath = [sourcePath stringByAppendingPathComponent:fileName];
     // 3.2生产目标文件的绝对路径
     NSString *destFilePath = [destPath stringByAppendingPathComponent:fileName];
     //        NSLog(@"%@", sourceFilePath);
     //        NSLog(@"%@", destFilePath);
     // 3.3利用NSFileManager拷贝文件
     [manager moveItemAtPath:sourceFilePath toPath:destFilePath error:nil];
     }
     */
    dispatch_apply(files.count, dispatch_get_global_queue(0, 0), ^(size_t index) {
        NSString *fileName = files[index];
        // 3.1生产原始文件的绝对路径
        NSString *sourceFilePath = [sourcePath stringByAppendingPathComponent:fileName];
        // 3.2生产目标文件的绝对路径
        NSString *destFilePath = [destPath stringByAppendingPathComponent:fileName];
        //        NSLog(@"%@", sourceFilePath);
        //        NSLog(@"%@", destFilePath);
        // 3.3利用NSFileManager拷贝文件
        [manager moveItemAtPath:sourceFilePath toPath:destFilePath error:nil];
    });

使用.png

在 GCD 中利用 dispatch_after 也得以完成延迟实践的职能:

九、栅栏 dispatch_barrier_async

1、功能:
1.阻挠前边的任务, 唯有先增多到队列中的职责=实施完结, 才会实践栅栏增多的天职
2.一旦栅栏后边还会有此外的职分, 那么必需等栅栏推行完结才会实行前边的别的职责
2、注意点:
1.比如想要使用栅栏, 那么就无法利用全局的现身队列
2.假设想使用栅栏, 那么具备的天职都必须要加多到同叁个类别中
3、实例:归并三种图片,异步函数并发队列十六线程下载图片,多少个线程同有时候下载图片,当二种图片下载达成-> 开启栅栏作用子线程中开展统一图片,合成图片甘休后,再会到主线程更新UI,
接纳,栅栏能够完成该要求,使用上面介绍的队列组也足以兑现该功用

- (void)barrier
{
    dispatch_queue_t queue = dispatch_queue_create("cjp", DISPATCH_QUEUE_CONCURRENT);
    //    dispatch_queue_t queue2 = dispatch_queue_create("cjp", DISPATCH_QUEUE_CONCURRENT);
    //    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

    __block UIImage *image1 = nil;
    __block UIImage *image2 = nil;
    // 1.开启一个新的线程下载第一张图片
    dispatch_async(queue, ^{
        NSURL *url = [NSURL URLWithString:@"https://img.alicdn.com/tps/i1/TB1AE.sFVXXXXaCXFXXwu0bFXXX.png"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:data];
        image1 = image;
        NSLog(@"图片1下载完毕");
    });
    // 2.开启一个新的线程下载第二张图片
    dispatch_async(queue, ^{
        NSURL *url = [NSURL URLWithString:@"https://www.baidu.com/img/bd_logo1.png"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:data];
        image2 = image;
        NSLog(@"图片2下载完毕");
    });

    // 3.开启一个新的线程, 合成图片
    // 栅栏
    dispatch_barrier_async(queue, ^{
       // 图片下载完毕
        NSLog(@"%@ %@", image1, image2);

        // 1.开启图片上下文
        UIGraphicsBeginImageContext(CGSizeMake(200, 200));
        // 2.将第一张图片画上去
        [image1 drawInRect:CGRectMake(0, 0, 100, 200)];
        // 3.将第二张图片画上去
        [image2 drawInRect:CGRectMake(100, 0, 100, 200)];
        // 4.从上下文中获取绘制好的图片
        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
        // 5.关闭上下文
        UIGraphicsEndImageContext();

        // 4.回到主线程更新UI
        dispatch_async(dispatch_get_main_queue(), ^{
            self.imageView.image = newImage;
// 将合并后的图片写到本地桌面:
            [UIImagePNGRepresentation(newImage) writeToFile:@"/Users/cjp/Desktop/123.png" atomically:YES];
        });

        NSLog(@"栅栏执行完毕了");
    });

    dispatch_async(queue, ^{
        NSLog(@"---------");
    });
    dispatch_async(queue, ^{
        NSLog(@"---------");
    });
    dispatch_async(queue, ^{
        NSLog(@"---------");
    });
}

二、推行职分:同步、异步、栅栏
同步 dispatch_sync
: 只好在近来线程中实践职分,不具备开启新线程的技术

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"延时 2.0 秒执行");});

十、队列组 dispatch_group_t

行使场景:分别异步推行2个耗费时间的操作,要等2个异步操作都推行完结后,再重返主线程实施操作
小心:这场景,使用方面的栅栏也可清除

dispatch_group_tgroup =  dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
    //执行1个耗时的异步操作
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
    //执行1个耗时的异步操作
});
dispatch_group_notify(group, dispatch_get_main_queue(),^{
    //等前面的异步操作都执行完毕后,回到主线程...
});
实例:异步线程中,下载两种图片,在dispatch_group_notify通知中说明图片下载完-> 合并图片,合并图片结束后 ->再回到主线程中更新UI
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
     NSLog(@"%s", __func__);

    dispatch_queue_t queue = dispatch_queue_create("cjp", DISPATCH_QUEUE_CONCURRENT);

    __block UIImage *image1 = nil;
    __block UIImage *image2 = nil;

    dispatch_group_t group = dispatch_group_create();

    // 1.开启一个新的线程下载第一张图片
    dispatch_group_async(group, queue, ^{
        NSURL *url = [NSURL URLWithString:@"https://img.alicdn.com/tps/i1/TB1AE.sFVXXXXaCXFXXwu0bFXXX.png"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:data];
        image1 = image;
        NSLog(@"图片1下载完毕");
    });

    // 2.开启一个新的线程下载第二张图片
    dispatch_group_async(group, queue, ^{
        NSURL *url = [NSURL URLWithString:@"https://www.baidu.com/img/bd_logo1.png"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:data];
        image2 = image;
        NSLog(@"图片2下载完毕");
    });

    // 3.开启一个新的线程, 合成图片
    // 只要将队列放到group中, 队列中的任务执行完毕, group就会发出一个通知

    dispatch_group_notify(group, queue, ^{
        NSLog(@"%@ %@", image1, image2);
        // 1.开启图片上下文
        UIGraphicsBeginImageContext(CGSizeMake(200, 200));
        // 2.将第一张图片画上去
        [image1 drawInRect:CGRectMake(0, 0, 100, 200)];
        // 3.将第二张图片画上去
        [image2 drawInRect:CGRectMake(100, 0, 100, 200)];
        // 4.从上下文中获取绘制好的图片
        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
        // 5.关闭上下文
        UIGraphicsEndImageContext();

        // 4.回到主线程更新UI
        dispatch_async(dispatch_get_main_queue(), ^{
            self.imageView.image = newImage;
            [UIImagePNGRepresentation(newImage) writeToFile:@"/Users/cjp/Desktop/123.png" atomically:YES];
        });
    });
}

dispatch_sync(dispatch_queue_tqueue, dispatch_block_tblock);

在延迟实施中,dispatch_after 函数本人是贰个异步函数,此中的种类也足以运用自定义的行列,它的庐山真面目目是延迟 2 秒再将职务交给到行列中,进而完毕延迟施行的功力。

小心:使用sync函数往当前串行队列中拉长职责,会卡住当前的串行队列

在过去大家驾驭能够应用 for 循环和 block 实行遍历,在 GCD 中我们也得以利用 dispatch_apply 函数进行高效迭代。

异步 dispatch_async:能够在新的线程中实行职分,具有开启新线程的本领

dispatch_queue_t queue = dispatch_get_global_queue; dispatch_apply(10, queue, ^ { NSLog(@"%zd --- %@", i, [NSThread currentThread]);});

dispatch_async(dispatch_queue_tqueue, dispatch_block_tblock);

皇家娱乐在线app,在 dispatch_apply 函数中的多少个参数分别表示着索要遍历的次数,存放任务的系列以至索引(就相当于for 循环中的 i )。

其他贰个实践职务的方法:dispatch_barrier_async
栅栏

注意:1. 快速迭代中的队列只能使用并发队列,不要使用串行队列或主队列,使用串行队列时就相当于 for 循环,使用主队列会造成死锁

气象:在前头的任务执行实现后它才试行,何况它背后的任务等它执行到位未来才会推行
瞩目:那几个queue不可能是全局的面世队列
dispatch_barrier_async(dispatch_queue_tqueue, dispatch_block_tblock);

2. 在快速迭代中,会开启子线程与主线程一起并发执行任务,执行顺序是不固定的

上边有详实表明

必要:同一时间下载图片一和图片二,当两张图纸均下载完结后合成使之成为一张图纸。

三、队列:串行 与 并行
使用dispatch_queue_create函数创制队列

在早先大家得以选取 GCD 中的栅栏函数解决那几个难题,具体的笔触为:使用异步函数 并发队列开启子线程来还要下载图片,然后增加一个栅栏函数进行拦截,最终在栅栏函数之后进行合成图片的职分,这里需求留意的是在合成图片的子线程中必要再次来到主线程(异步函数

dispatch_queue_t dispatch_queue_create( const char *label, //队列名称 dispatch_queue_attr_t attr //队列的种类卡塔尔(قطر‎;

  • 主队列)举办浮现图片。

1、并发
队列:(ConcurrentDispatch Queue)

实际除却,大家也可以选取队列组来化解那些标题,当队列组中负有的职务都实践达成,就能够执行dispatch_group_notify 函数。

能够让多个职责并发(同期)推行
(自动开启八个线程同期奉行职责)注意:并发成效唯有在异步(dispatch_async)函数下才使得
,因为异步函数才能有开启新线程的手艺,而一同函数只可以在这个时候此刻线程中实行不抱有开启线程的力量。

本文由68399皇家赌场发布于呼叫中心培训课程,转载请注明出处:的常用函数

关键词: 68399皇家赌场 多线程 博客 常用 OC

上一篇:MAC下cocoapods安装以及使用

下一篇:没有了

最火资讯