iOS:dispatch_block_t操作

通过 GCD 提供的方法来将一些需要耗时操作放到非主线程上做,使得 App 能够运行的更加流畅响应更快。但是使用 GCD 时需要注意避免可能引起线程爆炸和死锁的情况,还有非主线程处理任务也不是万能的,如果一个处理需要消耗大量内存或者大量CPU操作 GCD 也没法帮你,只能通过将处理进行拆解分步骤分时间进行处理才比较妥当。

一、dispatch_block_t应用

1、dispatch_block_t初始化

1> dispatch_block_create

dispatch_block_t dispatch_block_create(dispatch_block_flags_t flags, dispatch_block_t block);

flags的类型为 dispatch_block_flags_t 的枚举,用于设置 block 的标记,定义如下:

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,
);

2> dispatch_block_create_with_qos_class

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);

这种方式在创建 block 的同时可以指定了相应的优先级。

dispatch_qos_class_tqos_class_t的别名,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 未指明
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);

2、监听 block 执行结束

1> 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(@"执行超时");
    }
});

2> dispatch_block_notify

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函数不会阻塞当前线程。

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(@"---- 完成设置任务 ----");

3、取消block

dispatch_block_cancel

void dispatch_block_cancel(dispatch_block_t block);

取消操作使将来执行 dispatch block 立即返回,但是对已经在执行的 dispatch block 没有任何影响。

二、性能优化相关应用

1> 异步处理事件

2> 需要耗时长的任务

GCD 的 block 通过 dispatch_block_create_with_qos_class 方法指定队列的 QoS 为 QOS_CLASS_UTILITY。这种 QoS 系统会针对大的计算,I/O,网络以及复杂数据处理做电量优化。

3> 避免线程爆炸

举个例子,下面的写法就比较危险,可能会造成线程爆炸和死锁:

for (int i = 0; i < 999; i++) { 
dispatch_async(q, ^{…}); 
} 
dispatch_barrier_sync(q, ^{});

1、使用串行队列
2、使用 NSOperationQueues 的并发限制方法NSOperationQueue.maxConcurrentOperationCount
3、使用GCD信号量dispatch_semaphore控制线程最大并发

4> I/O 性能优化

一般出发点:

1、将零碎的内容作为一个整体进行写入 ;
2、使用合适的 I/O 操作 API ;
3、使用合适的线程 ;
4、使用 NSCache 做缓存能够减少 I/O;
截屏2020-11-06 下午5.56.22.png

参考链接:
深入剖析 iOS 性能优化
GCD 之任务操作(Dispatch Block)

你可能感兴趣的:(iOS:dispatch_block_t操作)