ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

iOS: GCD高级API

iOS: GCD高级API 文章目录GCD常用高级APIdispatch_once: 只执行一次最经典的用途: 单例为什么这里不用 ifdispatch_after它不是“创建一个定时线程”dispatch_group: 等待多个异步任务完成group_enter / group_leavegroup 的核心思想dispatch_group_async使用场景:notify 和 waitnotifydiaptch_barrier: 并发队列中的“屏障”dispath_semaphore: 信号量创建 semaphorewait 与 signalGCD常用高级API常用的高级API有:dispatch_once 单例dispatch_group 多任务完成通知dispatch_barrier 读写锁思想dispatch_semapbore 控制并发数量dispatch_once: 只执行一次这是GCD最简单, 也是最经典的API-(void)viewDidLoad{[superviewDidLoad];for(inti0;i4;i){[selftest];NSLog(执行完成);}}-(void)test{staticdispatch_once_t onceToken;dispatch_once(onceToken,^{NSLog(只执行一次);});}打印结果如下:可以观察到, 无论这个代码被调用多少次, 最终Block 只会执行一次最经典的用途: 单例(instancetype)sharedInstance{staticMyManager*instance;staticdispatch_once_t onceToken;dispatch_once(onceToken,^{instance[[MyManager alloc]init];});returninstance;}第一次调用 sharedInstance ↓ dispatch_once ↓ 创建 instance ↓ 返回第二次调用 sharedInstance ↓ 发现已经执行过 ↓ 不再执行 Block ↓ 直接返回 instance为什么这里不用 if可能有人会想到:staticMyManager*instance;if(instancenil){instance[[MyManager alloc]init];}这段代码在单线程的情况下看起来没问题但是如果是多线程线程 A 线程 B instancenil instancenil ↓ ↓ 创建 instance 创建 instance两个线程可能同时进入, 这就是典型的竞态问题dispatch_once 专门解决这种: 某段代码在整个进程生命周期中只需要安全地执行一次dispatch_afterNSLog(start);dispatch_after(dispatch_time(DISPATCH_TIME_NOW,2*NSEC_PER_SEC),dispatch_get_main_queue(),^{NSLog(2秒后);});看起来像: 2 秒后执行, 但是更准确地说:至少等待执行时间后, 再把任务提交到指定队列它不是“创建一个定时线程”错误理解dispatch_after ↓ 创建线程 ↓ 睡眠2秒 ↓ 执行不是这样。可以理解成dispatch_after ↓ 等待时间到达 ↓ 任务变得可以被调度 ↓ 提交到 queue ↓ queue 决定什么时候执行所以 dispatch_after 并不是严格保证 2 秒后的时候执行, 而是: 2 秒后才有资格执行dispatch_group: 等待多个异步任务完成这是非常重要的的API假设下载图片 A 下载图片 B 下载图片 C 全部完成以后 刷新 UI如果分别dispatch_async(queue,^{// A});dispatch_async(queue,^{// B});dispatch_async(queue,^{// C});我们不知道什么时候三个任务全部完成。这时候使用dispatch_group_t groupdispatch_group_create();group_enter / group_leavedispatch_queue_t queuedispatch_queue_create(concurrent_queue,DISPATCH_QUEUE_CONCURRENT);dispatch_group_t groupdispatch_group_create();dispatch_group_enter(group);dispatch_async(queue,^{NSLog(A完成);dispatch_group_leave(group);});dispatch_group_enter(group);dispatch_async(queue,^{NSLog(B完成);dispatch_group_leave(group);});dispatch_group_enter(group);dispatch_async(queue,^{NSLog(C完成);dispatch_group_leave(group);});dispatch_group_notify(group,dispatch_get_main_queue(),^{NSLog(A, B, C 全部完成);});理解成一个计数器enter ↓ 1 enter ↓ 1 enter ↓ 1 当前 3A 完成leave ↓ 2B 完成leave ↓ 1C 完成leave ↓ 0然后notify ↓ 执行group 的核心思想可以把它记成多个任务 ↓ Group ↓ 全部完成 ↓ Notify实际开发非常常见的模式请求用户信息 \ \ 请求订单信息 ----→ 全部完成 → 刷新页面 / 请求商品信息dispatch_group_async如果任务本身就是通过GCD提交, 可以进一步简化dispatch_group_t groupdispatch_group_create();dispatch_group_async(group,queue,^{NSLog(A);});dispatch_group_async(group,queue,^{NSLog(B);});dispatch_group_async(group,queue,^{NSLog(C);});dispatch_group_notify(group,dispatch_get_main_queue(),^{NSLog(全部完成);});dispatch_group_async 的写法是系统自动管理 enter 和 leave, 不需要手动调用使用场景:使用场景推荐写法是否需要手动 enter/leave任务内部没有异步操作如计算、读写文件、sleepdispatch_group_async不需要系统自动管理任务内部有异步回调如网络请求、GCD 延迟、UIView 动画dispatch_group_enterdispatch_group_leave需要手动管理在回调里调用leavenotify 和 waitGroup 有两个非常重要的方法dispatch_group_notify()dispatch_group_wait()notifydispatch_group_notify(group,queue,^{NSLog(完成);});特点: 异步等待当前线程:提交 notify - 继续执行waitdispatch_group_wait(group,DISPATCH_TIME_FOREVER);特点: 当前线程阻塞等待这和之前的 sync 与 async 是一样的diaptch_barrier: 并发队列中的“屏障”假设有读取 读取 读取 写入 读取 读取我们希望读1 ────── 读2 ────── 读3 ────── ↓ 写入 ↓ 读4 ────── 读5 ──────也就是前面的读任务全部完成以后执行写任务写任务完成以后后面的读任务才能执行。这就是 barrier。代码dispatch_queue_t queuedispatch_queue_create(com.demo.database,DISPATCH_QUEUE_CONCURRENT);dispatch_async(queue,^{NSLog(读 A);});dispatch_async(queue,^{NSLog(读 B);});dispatch_barrier_async(queue,^{NSLog(写入);});dispatch_async(queue,^{NSLog(读 C);});dispatch_async(queue,^{NSLog(读 D);});可以理解成Concurrent Queue A ──────────────┐ B ──────────────┤ ↓ Barrier ↓ 写入 ↓ C ──────────────┐ D ──────────────┘barrier 不是所有队列都有效dispatch_barrier_async真正具有上述屏障意义, 主要针对:自己创建的 concurrent queue, 在全局队列或者串行队列上,dispatch_barrier_async的行为会退化为普通的dispatch_async,完全失去隔离效果dispath_semaphore: 信号量假设有100个任务 ,但是同时最多允许 3 个任务执行,怎么办, 这个时候使用 semaphore 非常合适创建 semaphoredispatch_semaphore_t semaphoredispatch_semaphore_create(3);这里参数中的 3 可以理解成 3 个“许可证”第一个任务dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);拿走一个“许可证”, 执行任务完成任务后,dispatch_semaphore_signal(semaphore)“归还许可证”dispatch_queue_attr_t attrdispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL,QOS_CLASS_USER_INITIATED,0);dispatch_queue_t queuedispatch_queue_create(concurrent_queue,attr);dispatch_semaphore_t semaphoredispatch_semaphore_create(3);for(inti0;i100;i){dispatch_async(queue,^{dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);NSLog(task %d start,i);NSLog(task %d end,i);dispatch_semaphore_signal(semaphore);});}wait 与 signalwait - 拿资源signal - 还资源所以:dispatch_semaphore_wait(semaphore,...);使用资源dispatch_semaphore_signal(semaphore);
返回列表