​ 学习学习dispatch_block,在向队列中添加任务时,可以直接在对应的函数中添加 block。但是如果想对任务进行操作,比如监听任务、取消任务,就需要获取对应的 block

1 创建Block

  • 第一种方式如下:

    1
    dispatch_block_t dispatch_block_create(dispatch_block_flags_t flags, dispatch_block_t block);

    ​ 在该函数中,flags 参数用来设置 block 的标记,block 参数用来设置具体的任务。flags 的类型为 dispatch_block_flags_t 的枚举,用于设置 block 的标记,定义如下:

    1
    2
    3
    4
    5
    6
    7
    8
    DISPATCH_ENUM(dispatch_block_flags, unsigned long,
    DISPATCH_BLOCK_BARRIER = 0x1,
    DISPATCH_BLOCK_DETACHED = 0x2,
    DISPATCH_BLOCK_ASSIGN_CURRENT = 0x4,
    DISPATCH_BLOCK_NO_QOS_CLASS = 0x8,
    DISPATCH_BLOCK_INHERIT_QOS_CLASS = 0x10,
    DISPATCH_BLOCK_ENFORCE_QOS_CLASS = 0x20,
    );
  • 第二种方式如下:

    1
    2
    3
    dispatch_block_t dispatch_block_create_with_qos_class(dispatch_block_flags_t flags,
    dispatch_qos_class_t qos_class, int relative_priority,
    dispatch_block_t block);

    ​相比于 dispatch_block_create 函数,这种方式在创建 block 的同时可以指定了相应的优先级。dispatch_qos_class_tqos_class_t 的别名,定义如下:

    1
    2
    3
    4
    5
    #if __has_include(<sys/qos.h>)
    typedef qos_class_t dispatch_qos_class_t;
    #else
    typedef unsigned int dispatch_qos_class_t;
    #endif

    qos_class_t 是一种枚举,有以下类型:

    • QOS_CLASS_USER_INTERACTIVE:user interactive 等级表示任务需要被立即执行,用来在响应事件之后更新 UI,来提供好的用户体验。这个等级最好保持小规模。
    • QOS_CLASS_USER_INITIATED:user initiated 等级表示任务由 UI 发起异步执行。适用场景是需要及时,结果同时又可以继续交互的时候。
    • QOS_CLASS_DEFAULT:default 默认优先级
    • QOS_CLASS_UTILITY:utility 等级表示需要长时间运行的任务,伴有用户可见进度指示器。经常会用来做计算,I/O,网络,持续的数据填充等任务。这个任务节能。
    • QOS_CLASS_BACKGROUND:background 等级表示用户不会察觉的任务,使用它来处理预加载,或者不需要用户交互和对时间不敏感的任务。
    • QOS_CLASS_UNSPECIFIED:unspecified 未指明

    egg:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    dispatch_queue_t concurrentQuene = dispatch_queue_create("concurrentQuene", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_block_t block = dispatch_block_create(0, ^{
    NSLog(@"normal do some thing...");
    });
    dispatch_async(concurrentQuene, block); dispatch_block_t qosBlock = dispatch_block_create_with_qos_class(0, QOS_CLASS_USER_INTERACTIVE, 0, ^{
    NSLog(@"qos do some thing...");
    });
    dispatch_async(concurrentQuene, qosBlock);
    1
    2
    LQHelper[1528:112987] qos do some thing...
    LQHelper[1528:112985] normal do some thing...

2 监听 block 执行结束

​ 有时我们需要等待特定的 block 执行完成之后,再去执行其他任务。有两种方法可以获取到指定 block 执行结束的时机。

  • 第一种方式如下:

    1
    long dispatch_block_wait(dispatch_block_t block, dispatch_time_t timeout);

    ​ 该函数会阻塞当前线程进行等待。传入需要设置的 block 和等待时间 timeout。timeout 参数表示函数在等待 block 执行完毕时,应该等待多久。如果执行 block 所需的时间小于 timeout,则返回 0,否则返回非 0 值。此参数也可以取常量 DISPATCH_TIME_FOREVER,这表示函数会一直等待 block 执行完,而不会超时。可以使用 dispatch_time 函数和 DISPATCH_TIME_NOW 常量来方便的设置具体的超时时间。

    ​ 如果 block 执行完成,dispatch_block_wait 就会立即返回。不能使用 dispatch_block_wait 来等待同一个 block 的多次执行全部结束;这种情况可以考虑使用 dispatch_group_wait 来解决。也不能在多个线程中,同时等待同一个 block 的结束。同一个 block 只能执行一次,被等待一次。

    注意:因为 dispatch_block_wait 会阻塞当前线程,所以不应该放在主线程中调用。

    egg:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    dispatch_queue_t concurrentQuene = dispatch_queue_create("concurrentQuene", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(concurrentQuene, ^{
    dispatch_queue_t allTasksQueue = dispatch_queue_create("allTasksQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_block_t block = dispatch_block_create(0, ^{
    NSLog(@"开始执行");
    [NSThread sleepForTimeInterval:3];
    NSLog(@"结束执行");
    }); dispatch_async(allTasksQueue, block);
    // 等待时长,10s 之后超时
    dispatch_ 大专栏  GCD学习 —— 三time_t timeout = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC));
    long resutl = dispatch_block_wait(block, timeout);
    if (resutl == 0) {
    NSLog(@"执行成功");
    } else {
    NSLog(@"执行超时");
    }
    });
    1
    2
    3
    4
    5
    6
    7
    8
    执行结果:(把上面的sleepForTimeInterval:时间设置成3s)
    LQHelper[1582:121193] 开始执行
    LQHelper[1582:121194] 结束执行
    LQHelper[1582:121193] 执行成功
    执行结果:(把上面的sleepForTimeInterval:时间设置成12s)
    LQHelper[1582:121193] 开始执行
    LQHelper[1582:121194] 执行超时
    LQHelper[1582:121193] 结束执行
  • 第二种方法如下:

    1
    void dispatch_block_notify(dispatch_block_t block, dispatch_queue_t queue, dispatch_block_t notification_block);

    ​ 该函数接收三个参数,第一个参数是需要监视的 block,第二个参数是监听的 block 执行结束之后要提交执行的队列 queue,第三个参数是待加入到队列中的 block。 和 dispatch_block_wait 的不同之处在于:dispatch_block_notify 函数不会阻塞当前线程。

    egg:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    NSLog(@"---- 开始设置任务 ----");
    dispatch_queue_t serialQueue = dispatch_queue_create("com.itachi.serialqueue", DISPATCH_QUEUE_SERIAL); // 耗时任务
    dispatch_block_t taskBlock = dispatch_block_create(0, ^{
    NSLog(@"开始耗时任务");
    [NSThread sleepForTimeInterval:2.f];
    NSLog(@"完成耗时任务");
    }); dispatch_async(serialQueue, taskBlock); // 更新 UI
    dispatch_block_t refreshUI = dispatch_block_create(0, ^{
    NSLog(@"更新 UI");
    }); // 设置监听
    dispatch_block_notify(taskBlock, dispatch_get_main_queue(), refreshUI);
    NSLog(@"---- 完成设置任务 ----");
    1
    2
    3
    4
    5
    6
    执行结果:
    LQHelper[1615:127135] ---- 开始设置任务 ----
    LQHelper[1615:127135] ---- 完成设置任务 ----
    LQHelper[1615:127227] 开始耗时任务
    LQHelper[1615:127227] 完成耗时任务
    LQHelper[1615:127135] 更新 UI

3 任务的取消

iOS8 后 GCD 支持对 dispatch block 的取消。方法如下:

1
void dispatch_block_cancel(dispatch_block_t block);

​ 这个函数用异步的方式取消指定的 block。取消操作使将来执行 dispatch block 立即返回,但是对已经在执行的 dispatch block 没有任何影响。当一个 block 被取消时,它会立即释放捕获的资源。如果要在一个 block 中对某些对象进行释放操作,在取消这个 block 的时候,需要确保内存不会泄漏。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
dispatch_queue_t serialQueue = dispatch_queue_create("com.itachi.serialqueue", DISPATCH_QUEUE_SERIAL);
// 耗时任务
dispatch_block_t firstTaskBlock = dispatch_block_create(0, ^{
NSLog(@"开始第一个任务");
[NSThread sleepForTimeInterval:1.5f];
NSLog(@"结束第一个任务");
}); // 耗时任务
dispatch_block_t secTaskBlock = dispatch_block_create(0, ^{
NSLog(@"开始第二个任务");
[NSThread sleepForTimeInterval:2.f];
NSLog(@"结束第二个任务");
}); dispatch_async(serialQueue, firstTaskBlock);
dispatch_async(serialQueue, secTaskBlock); // 等待1s,让第一个任务开始运行
[NSThread sleepForTimeInterval:1]; dispatch_block_cancel(firstTaskBlock);
NSLog(@"尝试过取消第一个任务"); dispatch_block_cancel(secTaskBlock);
NSLog(@"尝试过取消第二个任务");
1
2
3
4
5
执行结果:
LQHelper[1645:130881] 开始第一个任务
LQHelper[1645:130771] 尝试过取消第一个任务
LQHelper[1645:130771] 尝试过取消第二个任务
LQHelper[1645:130881] 结束第一个任务

可见 dispatch_block_cancel 对已经在执行的任务不起作用,只能取消尚未执行的任务。

转载自GCD 之任务操作

GCD学习 —— 三的更多相关文章

  1. HTTP学习三:HTTPS

    HTTP学习三:HTTPS 1 HTTP安全问题 HTTP1.0/1.1在网络中是明文传输的,因此会被黑客进行攻击. 1.1 窃取数据 因为HTTP1.0/1.1是明文的,黑客很容易获得用户的重要数据 ...

  2. TweenMax动画库学习(三)

    目录               TweenMax动画库学习(一)            TweenMax动画库学习(二)            TweenMax动画库学习(三)           ...

  3. 多线程-GCD学习笔记

    ********************************* 基本概念 *********************************** 1. Grand Central Dispatch ...

  4. Struts2框架学习(三) 数据处理

    Struts2框架学习(三) 数据处理 Struts2框架框架使用OGNL语言和值栈技术实现数据的流转处理. 值栈就相当于一个容器,用来存放数据,而OGNL是一种快速查询数据的语言. 值栈:Value ...

  5. 4.机器学习——统计学习三要素与最大似然估计、最大后验概率估计及L1、L2正则化

    1.前言 之前我一直对于“最大似然估计”犯迷糊,今天在看了陶轻松.忆臻.nebulaf91等人的博客以及李航老师的<统计学习方法>后,豁然开朗,于是在此记下一些心得体会. “最大似然估计” ...

  6. DjangoRestFramework学习三之认证组件、权限组件、频率组件、url注册器、响应器、分页组件

    DjangoRestFramework学习三之认证组件.权限组件.频率组件.url注册器.响应器.分页组件   本节目录 一 认证组件 二 权限组件 三 频率组件 四 URL注册器 五 响应器 六 分 ...

  7. [ZZ] 深度学习三巨头之一来清华演讲了,你只需要知道这7点

    深度学习三巨头之一来清华演讲了,你只需要知道这7点 http://wemedia.ifeng.com/10939074/wemedia.shtml Yann LeCun还提到了一项FAIR开发的,用于 ...

  8. SVG 学习<三>渐变

    目录 SVG 学习<一>基础图形及线段 SVG 学习<二>进阶 SVG世界,视野,视窗 stroke属性 svg分组 SVG 学习<三>渐变 SVG 学习<四 ...

  9. Android JNI学习(三)——Java与Native相互调用

    本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Nati ...

随机推荐

  1. 初次运行Git前的配置

    初次运行Git前的配置 一.初次运行 Git 前的配置 一般在新的系统上,我们都需要先配置下自己的 Git 工作环境.配置工作只需一次,以后升级时还会沿用现在的配置.当然,如果需要,你随时可以用相同的 ...

  2. systemd[1]: mariadb.service: Can't open PID file /data/mariadb/mysql/30-mariadb-1.pid (yet?) after start: No such file or directory

    环境:Centos8 编译安装Mariadb-10.4.11,安装到make install都没有问题,添加服务启动脚本到/lib/systemd/system/,服务启动脚本名为mariadb.se ...

  3. 表查询语句及使用-连表(inner join-left join)-子查询

    一.表的基本查询语句及方法 from. where. group by(分组).having(分组后的筛选).distinct(去重).order by(排序).  limit(限制) 1.单表查询: ...

  4. 吴裕雄--天生自然C语言开发:函数指针

    #include <stdio.h> int max(int x, int y) { return x > y ? x : y; } int main(void) { /* p 是函 ...

  5. B. Split a Number(字符串加法)

    Dima worked all day and wrote down on a long paper strip his favorite number nn consisting of ll dig ...

  6. linux进程(一)

    回顾:CentOS6的启动过程开机自检->找硬盘->操作系统->内核->进程->登录 Systemd借鉴了很多launchd的思想,他的重要特性如下:1.同SysVini ...

  7. java 的ConcurrentHashMap底层数据结构

    集合是编程中最常用的数据结构.而谈到并发,几乎总是离不开集合这类高级数据结构的支持.比如两个线程需要同时访问一个中间临界区(Queue),比如常会用缓存作为外部文件的副本(HashMap).这篇文章主 ...

  8. StartDT AI Lab | 视觉智能引擎——Re-ID赋能线下场景顾客数字化

    人货场的思路是整个新零售数字化链路的核心,人是整个业务生命周期的起始点,图像算法的首要目标就是从图像中得到“人” .前一篇我们主要讲了Face ID的发展,Face ID帮助商家赋能了线下用户画像,把 ...

  9. 83)PHP,配置文件功能

    首选配置文件应该在  我们的应用application目录中,这样针对每一应用,都有自己的配置文件. 我觉得配置文件的名字很有意思,首先是  名字.config.php 格式就是 return arr ...

  10. python3下scrapy爬虫(第六卷:利用cookie模拟登陆抓取个人中心页面)

    之前我们爬取的都是那些无需登录就要可以使用的网站但是当我们想爬取自己或他人的个人中心时就需要做登录,一般进入登录页面有两种 ,一个是独立页面登陆,另一个是弹窗,我们先不管验证码登陆的问题 ,现在试一下 ...