iOS开发之浅谈GCD的使用(二)
2015-12-25 10:29
218 查看
iOS开发之浅谈GCD的使用(二)
系统提供的global队列
上次说到系统给我们提供了四个队列, 分别是global队列的四种优先级. 我们打印四个优先级队列的地址, 可以看到四个优先级队列的地址是不同的, 所以这是四个不同的队列, 然后我们在同一个程序不同的地方去打印, 发现同优先级的队列的地址是相同的. 所以可以得出, 在一个程序中, 在任何地方调用dispatch_get_global_queue 得到相同优先级的队列, 都是同一个.(类似于单例)在系统的global队列中追加任务的方法是
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ NSLog(@"%@", globalDefaultPriority); });
dispatch_after与dispatch_time_t
这个函数的目的是, 在一段时间后把block中的任务追加到一个队列中, 经常被用作延迟执行. 例如: 我要把一段代码在2秒后放入主队列中执行.//建立一个dispatch_time_t, 代表着从现在开始计算, 2秒后 dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC); //这段代码就是将输出语句在两秒后追加进主队列 dispatch_after(time, dispatch_get_main_queue(), ^{ NSLog(@"%@", globalHighPriority); });
需要注意一点, 这个函数是N秒后将一段代码追加进队列中, 并不是N秒后直接执行, 加入将一个线程睡眠2秒, 然后将一个输出语句在2秒后追加进这个线程, 那么这个输出语句将会在4秒后才执行.
group 组队列
在开发中, 我们经常碰到这种情况, 我们开辟了三个线程, 然后我们需要等到这几个线程都执行完了后, 调用一段代码, 而这三个线程是用的并发队列, 我们并不知道哪个是最后一个执行, 这个时候我们就要用到group组队列, 使用group我们可以监听到一组队列中所有的任务是不是都执行完.//我们先获取到一个并发队列 dispatch_queue_t globalQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //创建一个组 dispatch_group_t group = dispatch_group_create(); //向这个队列追加两个任务 dispatch_group_async(group, globalQueueDefault, ^{ NSLog(@"block1"); }); dispatch_group_async(group, globalQueueDefault, ^{ NSLog(@"block2"); }); //在两个任务都执行完之后, 才去输出结束处理, 在组里面的任务执行结束之后会调用这个方法dispatch_group_notify dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"结束处理"); });
dispatch_barrier_async
我们对本地文件进行读写的时候 不能用并行同时进行读取和写入 这样会造成很多问题 例如:数据竞争问题 由于可能在写入之前先读取 所以可能造成数据混乱还有可能导致程序异常结束 但是我们可以进行同时读取的操作 前提是写入必须在读取之前 所以可以将读取处理追加到Concurrent Queue中 写入处理在任何一个读取处理都没有进行之前 追加到Serial Queue中 虽然可以用Queue 和dispatch_set_target_queue实现 但是很麻烦 所以系统给我们提供了 dispatch_barrier_async 这个函数会等待追加到Concurrent Dispatch Queue上得并行执行全部结束后 再将指定的处理追加到这个Concurrent Dispatch Queue上 等这个追加处理完成后再将Concurrent Dispatch Queue恢复为一般的动作先说一下错误的写法
//这样写会出现那样的问题(错误的) dispatch_async(global, ^{ NSLog(@"读取1"); }); dispatch_async(global, ^{ NSLog(@"读取2"); }); dispatch_async(global, ^{ NSLog(@"读取3"); }); dispatch_async(global, ^{ NSLog(@"写入"); }); dispatch_async(global, ^{ NSLog(@"读取4"); });
以上的写法会造成读取与写入混乱 , 会产生很严重的后果.
正确的写法应该是:
dispatch_async(global, ^{ NSLog(@"读取1"); }); dispatch_async(global, ^{ NSLog(@"读取2"); }); dispatch_async(global, ^{ NSLog(@"读取3"); }); dispatch_barrier_async(global, ^{ NSLog(@"写入1"); }); dispatch_async(global, ^{ NSLog(@"读取4"); });
以上是正确写法, 在写入时使用了dispatch_barrier_async, 这样系统会等待读取1、读取2、读取3这三个任务都执行结束之后再将写入1这个任务追加进队列中, 等写入1执行完毕, 再将队列恢复为一般的状态.
semaphore GCD的引用计数
semaphore是持有计数信号 类似过马路的手旗 可以通过时举起 不可以通过时放下手旗 Dispatch Semaphore中 使用计数来实现该功能, 计数为0时等待, 计数为1或者大于1的时候 减去1而不等待以下写法是错误的, 可能会产生崩溃.
for (int i = 0; i < 1000; i++) { dispatch_async(global, ^{ [arr addObject:[NSNumber numberWithInt:i]]; }); }
以下的写法是正确的 , 使用Semaphore来控制线程的执行.
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); for (int i = 0; i < 1000; i++) { dispatch_async(global, ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); [arr addObject:[NSNumber numberWithInt:i]]; dispatch_semaphore_signal(semaphore); }); }
还有另一个用法, dispatch I/O
输入输出控制 具体细节我们会在后面中探讨.
欢迎大家来积极讨论呦~~~~
相关文章推荐
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 不可修补的 iOS 漏洞可能导致 iPhone 4s 到 iPhone X 永久越狱
- iOS 12.4 系统遭黑客破解,漏洞危及数百万用户
- 每日安全资讯:NSO,一家专业入侵 iPhone 的神秘公司
- [转][源代码]Comex公布JailbreakMe 3.0源代码
- 讲解iOS开发中基本的定位功能实现
- js判断客户端是iOS还是Android等移动终端的方法
- IOS开发环境windows化攻略
- iOS开发之路--微博“更多”页面
- 浅析iOS应用开发中线程间的通信与线程安全问题
- 检测iOS设备是否越狱的方法
- .net平台推送ios消息的实现方法
- 探讨Android与iOS,我们将何去何从?
- Android、iOS和Windows Phone中的推送技术详解
- IOS 改变键盘颜色代码
- 举例详解iOS开发过程中的沙盒机制与文件
- Android和IOS的浏览器中检测是否安装某个客户端的方法
- 分享一个iOS下实现基本绘画板功能的简单方法