GCD全解-09-dispatch_block

版权声明:知识版权是属于全人类的! 欢迎评论与转载!!! https://blog.csdn.net/zhuge1127/article/details/82526089

为什么要学dispatch_block?

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

dispatch_block_flags

DISPATCH_ENUM(dispatch_block_flags, unsigned long,
    DISPATCH_BLOCK_BARRIER,
    DISPATCH_BLOCK_DETACHED,
    DISPATCH_BLOCK_ASSIGN_CURRENT,
    DISPATCH_BLOCK_NO_QOS_CLASS,
    DISPATCH_BLOCK_INHERIT_QOS_CLASS,
    DISPATCH_BLOCK_ENFORCE_QOS_CLASS
);

dispatch_block_create创建

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

# 相比于 dispatch_block_create 函数,这种方式在创建 block 的同时可以指定了相应的优先级。
# dispatch_qos_class_t 是 qos_class_t 的别名
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_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 未指明

demo

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_DEFAULT, 0, ^{ 
    NSLog(@"qos do some thing..."); 
}); 
dispatch_async(concurrentQuene, qosBlock);

监听 block 执行结束

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

dispatch_block_wait

long dispatch_block_wait(dispatch_block_t block, dispatch_time_t timeout);

#======================#======================#======================


# 如何使用
## 因为 dispatch_block_wait 会阻塞当前线程,所以不应该放在主线程中调用。创建一个新的并队列执行
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_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(@"执行超时"); 
    } 
});

dispatch_block_notify

第一个Block是操作的Block, 第二个Block是完成操作之后的Block
dispatch_block_notify(dispatch_block_t block, dispatch_queue_t queue,
        dispatch_block_t notification_block);

#======================#======================#======================


NSLog(@"---- 开始设置任务 ----"); 
dispatch_queue_t serialQueue = dispatch_queue_create("com.fyf.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(@"---- 完成设置任务 ----");

GCD的取消:dispatch_block_cancel

iOS8 后 GCD 支持对 dispatch block 的取消。

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

# 取消当前已获取资源但尚未执行的Block
void dispatch_block_cancel(dispatch_block_t block);

# zero if not canceled. 下面的方法用来测试Block是否成功的取消了
long dispatch_block_testcancel(dispatch_block_t block);

#======================#======================#======================

dispatch_queue_t serialQueue = dispatch_queue_create("com.fyf.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(@"尝试过取消第二个任务");

开始第一个任务
尝试过取消第一个任务
尝试过取消第二个任务
结束第一个任务

    可以发现第二个任务可以顺利取消

猜你喜欢

转载自blog.csdn.net/zhuge1127/article/details/82526089