版本:iOS13.5
block.h
dispatch其他文件通道
索引
-
dispatch_block_create
根据现有的调试块和给定的标志创建一个新的调试块 -
dispatch_block_create_with_qos_class
根据现有块和给定的标志创建一个新的调度块对象,并为其分配指定的QOS类和相对优先级。 -
dispatch_block_perform
根据现有的调试块和给定的标志创建一个新的调试块并同步执行块,再释放块对象 -
dispatch_block_wait
同步等待,直到指定的块对象的执行完成或超时为止。(该方法会堵塞当前线程) -
dispatch_block_notify
在block执行后将notification_block提交给队列queue并执行。 -
dispatch_block_cancel
异步取消block -
dispatch_block_testcancel
测试block是否已取消
详解
- 根据现有的调试块和给定的标志创建一个新的调试块
dispatch_block_t dispatch_block_create(dispatch_block_flags_t flags, dispatch_block_t block);
flags是一个枚举
DISPATCH_OPTIONS(dispatch_block_flags, unsigned long,
//该标志指示调度块对象在提交到DISPATCH_QUEUE_CONCURRENT队列时会充当屏障块
//block未执行结束前,队列中下一个的block不会调用,直到本次block执行结束,保证线程安全
DISPATCH_BLOCK_BARRIER = 0x1,
//该标志指示应该执行与当前执行上下文属性无关的调度块对象。
//如果直接调用,则块对象将在block的持续时间内从调用线程中删除其他属性。
//如果提交给队列,则将使用队列的属性(或专门分配给该块对象的任何属性)执行block。
DISPATCH_BLOCK_DETACHED = 0x2,
//该标志指示应为调度块对象分配创建块对象时当前的执行上下文属性。
//如果直接调用,则块对象将在block的持续时间内将这些属性应用于调用线程。
//如果将块对象提交到队列,则此标志将替换默认行为,将提交的块对象与提交时当前的执行上下文属性相关联
DISPATCH_BLOCK_ASSIGN_CURRENT = 0x4,
//该标志指示不应将QOS类分配给调度块对象
//如果直接调用,则块对象将与调用线程的QOS类一起执行。
//如果将块对象提交到队列,它将替换默认的行为,即在提交时将提交的块对象与当前的QOS类相关联
DISPATCH_BLOCK_NO_QOS_CLASS = 0x8,
//该标志指示执行提交到队列的调度块对象应优先于分配给队列的QOS类,而不是分配给该块的QOS类
//当将调度块对象提交到队列以进行异步执行时,此标志是默认设置;当直接调用调度块对象时,此标志无效
DISPATCH_BLOCK_INHERIT_QOS_CLASS = 0x10,
//该标志指示执行提交到队列的调度块对象应优先于分配给该队列的QOS类,而不是分配给队列的QOS类。
//当将调度块对象提交到队列以进行同步执行或直接调用调度块对象时,此标志是默认设置。
DISPATCH_BLOCK_ENFORCE_QOS_CLASS = 0x20,
);
block是一个回调块void (^dispatch_block_t)(void)
- 根据现有块和给定的标志创建一个新的调度块对象,并为其分配指定的QOS类和相对优先级。
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);
qos_class是一个枚举
__QOS_ENUM(qos_class, unsigned int,
//任务需要被立即执行,用来在响应事件之后更新 UI,来提供好的用户体验。这个等级最好保持小规模。
QOS_CLASS_USER_INTERACTIVE = 0x21,
//任务由 UI 发起异步执行。适用场景是需要及时结果同时又可以继续交互的时候。
QOS_CLASS_USER_INITIATED = 0x19,
//默认优先级
QOS_CLASS_DEFAULT = 0x15,
//需要长时间运行的任务,伴有用户可见进度指示器。经常会用来做计算,I/O,网络,持续的数据填充等任务。这个任务节能。
QOS_CLASS_UTILITY = 0x11,
//用户不会察觉的任务,使用它来处理预加载,或者不需要用户交互和对时间不敏感的任务。
QOS_CLASS_BACKGROUND = 0x09,
//未指明
QOS_CLASS_UNSPECIFIED = 0x00,
);
relative_priority QOS类中的相对优先级。该值是与最大支持的调度程序优先级的负偏移量。传递大于0或小于QOS_MIN_RELATIVE_PRIORITY
的值将导致返回NULL。
#define QOS_MIN_RELATIVE_PRIORITY (-15)
例:
//创建一个新的队列
dispatch_queue_t testQueue = dispatch_queue_create("testQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_block_t block1 = dispatch_block_create(0, ^{
NSLog(@"block1");
});
dispatch_async(testQueue, block1);
dispatch_block_t block2 = dispatch_block_create_with_qos_class(0, QOS_CLASS_DEFAULT, 0, ^{
NSLog(@"block2");
});
//同步执行
// block2();
//异步执行
dispatch_async(testQueue, block2);
- 根据现有的调试块和给定的标志创建一个新的调试块并同步执行块,再释放块对象
void dispatch_block_perform(dispatch_block_flags_t flags,
DISPATCH_NOESCAPE dispatch_block_t block);
例:
dispatch_block_t block2 = dispatch_block_create_with_qos_class(0, QOS_CLASS_DEFAULT, 0, ^{
NSLog(@"block2");
});
//同步执行 先创建再执行再释放
dispatch_block_perform(0, block2);
- 同步等待,直到指定的块对象的执行完成或超时为止。(该方法会堵塞当前线程)
long dispatch_block_wait(dispatch_block_t block, dispatch_time_t timeout);
timeout 超时时间 单位为纳秒,可使用N*NSEC_PER_SEC来变成秒
设置DISPATCH_TIME_FOREVER来将时间变成永远,表示会一直等待 block 执行,且不会超时
设置DISPATCH_TIME_NOW将时间设为现在,立即超时
也可设置成dispatch_time(DISPATCH_TIME_NOW, 2*NSEC_PER_SEC)
来自定义时间
返回一个long 非超时则返回0 超时返回非0
例:
dispatch_queue_t testQueue = dispatch_queue_create("testQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(testQueue, ^{
dispatch_block_t block3 = dispatch_block_create_with_qos_class(0, QOS_CLASS_DEFAULT, 0, ^{
NSLog(@"block3");
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//1秒后执行
block3();
});
// dispatch_time_t timeout = DISPATCH_TIME_NOW;//当前 立即超时
dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC);//3秒后超时
// dispatch_time_t timeout = 3000000 * NSEC_PER_SEC;//测试时发现需要多乘1000000才能表示秒,不知为何
// dispatch_time_t timeout = DISPATCH_TIME_FOREVER;//永不超时 一直等待
long result = dispatch_block_wait(block3, timeout);
NSLog(@"%ld", result);
});
输出:由于超时时间为3秒 dispatch_after为1秒后执行block3 所以不会超时 返回0
block3
0
- 在block执行后将notification_block提交给队列queue并执行。
void dispatch_block_notify(dispatch_block_t block, dispatch_queue_t queue,
dispatch_block_t notification_block);
queue 队列 可通过dispatch_queue_create("testQueue", DISPATCH_QUEUE_CONCURRENT)
创建;
例:
dispatch_block_t block4 = dispatch_block_create(0, ^{
NSLog(@"开始耗时任务block4");
[NSThread sleepForTimeInterval:2.f];
NSLog(@"完成耗时任务block4");
});
dispatch_block_t block5 = dispatch_block_create(0, ^{
NSLog(@"block5");
});
dispatch_block_notify(block4, dispatch_get_main_queue(), block5);
dispatch_async(testQueue, block4);//当这句话注释后会直接执行block5
输出:
开始耗时任务block4
完成耗时任务block4
block5
- 异步取消block
void dispatch_block_cancel(dispatch_block_t block);
该方法对已经在执行中的block没有影响。当一个 block 被取消时,它会立即释放捕获的资源。
例:
dispatch_queue_t testQueue = dispatch_queue_create("testQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_block_t block6 = dispatch_block_create(0, ^{
NSLog(@"开始耗时任务block6");
[NSThread sleepForTimeInterval:1.f];
NSLog(@"完成耗时任务block6");
});
dispatch_block_t block7 = dispatch_block_create(0, ^{
NSLog(@"开始耗时任务block7");
[NSThread sleepForTimeInterval:1.f];
NSLog(@"完成耗时任务block7");
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
dispatch_async(testQueue, block6);//block6运行时间 1s-2s
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
dispatch_async(testQueue, block7);//block7运行时间 2s-3s
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//1.5秒时 block6已经调用 不能成功取消 会在块执行完成后取消
dispatch_block_cancel(block6);
//1.5秒时 block7还未调用 可以成功取消
dispatch_block_cancel(block7);
});
输出:
开始耗时任务block6
完成耗时任务block6
- 测试block是否已取消
long dispatch_block_testcancel(dispatch_block_t block);
如果已取消,则返回非零;如果未取消,则返回零。
例:
dispatch_queue_t testQueue = dispatch_queue_create("testQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_block_t block6 = dispatch_block_create(0, ^{
NSLog(@"开始耗时任务block6");
[NSThread sleepForTimeInterval:1.f];
NSLog(@"完成耗时任务block6");
});
dispatch_block_t block7 = dispatch_block_create(0, ^{
NSLog(@"开始耗时任务block7");
[NSThread sleepForTimeInterval:1.f];
NSLog(@"完成耗时任务block7");
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
dispatch_async(testQueue, block6);//block6运行时间 1s-2s
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
dispatch_async(testQueue, block7);//block7运行时间 2s-3s
});
long cancle6 = dispatch_block_testcancel(block6);
long cancle7 = dispatch_block_testcancel(block7);
NSLog(@"cancle6 %ld cancle7 %ld", cancle6, cancle7);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//1.5秒时 block6已经调用 不能成功取消 会在块执行完成后取消
dispatch_block_cancel(block6);
//1.5秒时 block7还未调用 可以成功取消
dispatch_block_cancel(block7);
long cancle6 = dispatch_block_testcancel(block6);
long cancle7 = dispatch_block_testcancel(block7);
NSLog(@"cancle6 %ld cancle7 %ld", cancle6, cancle7);
});
输出:可以看出 虽然block6未成功取消 但是此时仍然为已取消状态
cancle6 0 cancle7 0
开始耗时任务block6
cancle6 1 cancle7 1
完成耗时任务block6