文章分享至我的个人技术博客: cainrun.github.io/15062229631…
上一篇, 我们简单的讲了一些使用
的小技巧, 如果没有看的朋友, 可以去玩转iOS开发:实战开发中的GCD Tips小技巧 (一)看.
- GCD
这次, 我们继续讲解小技巧.
通常我们使用队列组执行任务的时候是酱紫的:
- - (void) queueGroup {
- dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
- dispatch_group_t group = dispatch_group_create();
- dispatch_group_async(group, queue, ^{
- NSLog(@"执行任务, 当前线程为:%@", [NSThread currentThread]);
- });
- }
打印的结果:
- 2017-09-24 11:34:44.766052+0800 GCD-Tips[59653:3481972] 开始执行
- 2017-09-24 11:34:44.766606+0800 GCD-Tips[59653:3482075] 执行任务, 当前线程为:<NSThread: 0x604000464980>{number = 3, name = (null)}
但有时候, 我们会遇到一种情况, 就是没有办法直接使用队列组变量, 这个时候, 还有另外一种方式, 就是
和
- dispatch_group_enter
, 注意, 这两个方法是同时出现的:
- dispatch_group_leave
- - (void) gourpEnterAndLeave {
- dispatch_group_t group = dispatch_group_create();
- dispatch_group_enter(group);
- [self urlRequestSuccess: ^{
- NSLog(@"网络请求成功");
- dispatch_group_leave(group);
- }
- failure: ^{
- NSLog(@"网络请求失败");
- dispatch_group_leave(group);
- }];
- }
- - (void) urlRequestSuccess: (void( ^ )()) success failure: (void( ^ )()) failure {
- success();
- // failure();
- }
打印的结果:
- 2017
- -
- 09
- -
- 24
- 11
- :
- 46
- :
- 16.054410
- +
- 0800
- GCD-Tips[
- 60002
- :
- 3501228
- ] 开始执行
- 2017
- -
- 09
- -
- 24
- 11
- :
- 46
- :
- 16.054721
- +
- 0800
- GCD-Tips[
- 60002
- :
- 3501228
- ] 网络请求成功
这样子, 我们就可以把这个网络请求给打包起来, 但这里要注意一下, 不能同时调用两个
, 不然就会挂了.
- dispatch_group_leave
如果我们要添加结束任务的话, 可以有两种方式:
来通知, 任务已经结束.
- dispatch_group_notify
类似, 只不过是在可以添加延迟结束的时间, 但这里需要注意一点,
- dispatch_group_notify
会阻塞当前线程, 所以不要在
- dispatch_group_wait
中调用, 不然会阻塞主线程.
- 主线程
我们都知道
其实是一个栅栏方法, 它的作用就是在向某个队列插入一个
- dispatch_barrier_(a)sync
, 等到该
- block
执行完之后, 才会继续执行其他队列, 有点老大的味道.
- block
- - (void) queueBarrier {
- dispatch_queue_t queue = dispatch_queue_create("queueBarrier", DISPATCH_QUEUE_CONCURRENT);
- dispatch_async(queue, ^{
- NSLog(@"执行一, 当前线程:%@", [NSThread currentThread]);
- });
- dispatch_barrier_async(queue, ^{
- NSLog(@"大佬来了, 当前线程:%@", [NSThread currentThread]);
- });
- dispatch_async(queue, ^{
- NSLog(@"执行二, 当前线程:%@", [NSThread currentThread]);
- });
- }
打印的结果:
- 2017-09-24 12:44:36.151126+0800 GCD-Tips[61121:3585236] 开始执行
- 2017-09-24 12:44:36.151579+0800 GCD-Tips[61121:3585334] 执行一, 当前线程:<NSThread: 0x600000462e40>{number = 3, name = (null)}
- 2017-09-24 12:44:36.152335+0800 GCD-Tips[61121:3585334] 大佬来了, 当前线程:<NSThread: 0x600000462e40>{number = 3, name = (null)}
- 2017-09-24 12:44:36.154241+0800 GCD-Tips[61121:3585334] 执行二, 当前线程:<NSThread: 0x600000462e40>{number = 3, name = (null)}
PS:
只在自己创建的并发队列的才会有效, 如果是在全局并发队列, 串行队列,
- dispatch_barrier_(a)sync
效果是一样的, 这样子的话, 就会容易造成线程死锁, 所以这里要注意.
- dispatch_(a)sync
这里要补充两个东西,
和
- dispatch_set_context
.
- dispatch_set_finalizer_f
这里要注意一点
接受的
- dispatch_set_context
参数是为
- context
语言参数, 所以这里写的时候, 要注意一下:
- C
- typedef struct _Info {
- int age;
- }
- Info;
- void cleanStaff(void * context) {
- NSLog(@"In clean, context age: %d", ((Info * ) context) - >age);
- //释放,如果是new出来的对象,就要用delete
- free(context);
- }
- - (void) setContext {
- dispatch_queue_t queue = dispatch_queue_create("contextQueue", DISPATCH_QUEUE_SERIAL);
- // 初始化Data对象, 并且设置初始化值
- Info * myData = malloc(sizeof(Info));
- myData - >age = 100;
- // 绑定Context
- dispatch_set_context(queue, myData);
- // 设置finalizer函数,用于在队列执行完成后释放对应context内存
- dispatch_set_finalizer_f(queue, cleanStaff);
- dispatch_async(queue, ^{
- //获取队列的context数据
- Info * data = dispatch_get_context(queue);
- //打印
- NSLog(@"1: context age: %d", data - >age);
- //修改context保存的数据
- data - >age = 20;
- });
- }
打印一下结果:
- 2017-09-24 14:24:10.394129+0800 GCD-Tips[61881:3652088] 开始执行
- 2017-09-24 14:24:10.394547+0800 GCD-Tips[61881:3652274] 1: context age: 100
- 2017-09-24 14:24:10.394738+0800 GCD-Tips[61881:3652274] In clean, context age: 20
PS: 我们设置了
记得一定要释放掉, 不然就会造成内存泄漏.
- dispatch_set_context
除了这个之外, 我们还可以对
进行操作, 那么该怎么做呢
- Core Foundation
这里我们要创建一个
类, 继承与
- Model
:
- NSObject
- @interface GCDModel: NSObject
- @property(nonatomic, assign) NSInteger age;
- @end
- @implementation GCDModel
- - (void) dealloc {
- NSLog(@"%@ 释放了", NSStringFromClass([self class]));
- }
- @end
在这个类里面, 我们就简单操作, 只有一个属性和一个
方法, 具体操作:
- dealloc
- void cleanObjectStaff(void * context) {
- GCDModel * model = (__bridge GCDModel * ) context;
- NSLog(@"In clean, context age: %ld", model.age);
- // 释放内存
- CFRelease(context);
- }
- - (void) objectAndContext {
- dispatch_queue_t queue = dispatch_queue_create("objectQueue", DISPATCH_QUEUE_SERIAL);
- // 初始化Data对象, 并且设置初始化值
- GCDModel * model = [[GCDModel alloc] init];
- model.age = 20;
- // 绑定Context, 这里使用__bridge关键
- dispatch_set_context(queue, (__bridge_retained void * )(model));
- // 设置finalizer函数,用于在队列执行完成后释放对应context内存
- dispatch_set_finalizer_f(queue, cleanObjectStaff);
- dispatch_async(queue, ^{
- //获取队列的context数据
- GCDModel * model = (__bridge GCDModel * )(dispatch_get_context(queue));
- //打印
- NSLog(@"1: context age: %ld", model.age);
- //修改context保存的数据
- model.age = 120;
- });
- }
打印一下结果:
- 2017-09-24 14:40:34.024509+0800 GCD-Tips[62448:3676807] 开始执行
- 2017-09-24 14:40:34.024915+0800 GCD-Tips[62448:3676887] 1: context age: 20
- 2017-09-24 14:40:34.025236+0800 GCD-Tips[62448:3676887] In clean, context age: 120
- 2017-09-24 14:40:34.025706+0800 GCD-Tips[62448:3676887] GCDModel 释放了
这里我们要解释一下
关键字:
- __bridge
, 并且把内存管理权限从
- (CFBridgingRetain)
里拿到自己手里, 最后释放时要用
- ARC
来释放对象.
- CFRelease
转换成
- Core Foundation
对象
- Objective-C
, 并且将内存管理的权限交给
- (CFBridgingRelease)
.
- ARC
看到这里应该会有人问, 为什么要把内存管理拿到自己的手里, 而不是交给
- ARC
其实道理很简单, 如果是
管理的话, 一旦它检测到作用于完了之后, 你的对象就会释放了.
- ARC
那么你就无法将这个
添加到队列当中, 一旦添加就会给你报一个
- Context
错误, 所以我们为了确保不会被
- 野指针
给释放掉, 我们就需要自己去操作了.
- ARC
而上面那段代码的解释也很简单:
时候用
- dispatch_set_context
进行转换, 将
- __bridge_retained
的内存管理权限拿到我们自己手上进行管理.
- Context
来获取
- dispatch_get_context
的时候用关键字
- context
进行转换, 这样子可以维持
- __bridge
的内存管理权不变, 防止出了作用域
- context
就会被释放掉.
- Context
来释放掉
- CFRelease
, 这样子就可以保证内存得到释放, 不会造成内存泄漏的问题.
- context
好了, 额外补充的
小技巧到这里就差不多了, 如果以后还有更多的小技巧也会继续更新, 欢迎各位小伙伴们和我分享其他的使用技巧~~
- GCD
这里推荐几篇文章:
Grand Central Dispatch (GCD) Reference
Concurrency Programming Guide
Toll-Free Bridged Types
项目地址: github.com/CainRun/iOS…
来源: https://juejin.im/post/59fc981ff265da432d27756c