这段时间无业在家,在看iOS多线程相关的东西的时候就稍微研究了一下GCD,GCD由C语言实现,在Objective-C里调用它就是C语言的方法,在Swift则做了一层封装`DispatchObject`。 [TOC] ## 在Objective-C上的GCD 在Objective-C中常用的GCD代码块: ```objective-c //OC中单例的构造函数经常用到的,在应用生命周期里闭包的代码块只执行一次。 //Swift里没有了,这类的单例实现必须自己判断。 //在[Objective-C及Swift中的单例](http://blog.07coding.com/iOS/25.html)我有提及。 static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ }); //延时在主队列里处理闭包的内容 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ }); //异步在global里处理 dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{ //异步在主队列里处理 dispatch_async(dispatch_get_main_queue(), ^{ }); /*一定要避免这个代码块出现在主队列里,会死锁的。我在实际应用中没用过sync方法 dispatch_sync(dispatch_get_main_queue(), ^{ }); */ }); ``` >说个题外话,自己写管理类、封装网络请求的时候回调闭包或协议的时候一定要放在主队列里,不然会出问题的。工作上的样例:同事下载游戏本地包状态的回调没有放在主队列,然后当游戏下载完成初始化UI的时候控制台疯狂打印,UI初始化失败。问题找了老半天,还好NSLog打印的日志有队列ID,才排查出来(在这里我强烈建议Swift里不要使用`print`打印日志,我打印日志的工具是用[Loggerithm](https://github.com/honghaoz/Loggerithm)修改自己添加输出当前队列ID,后期应该会出现在我的博客上)。 我用的最多的是Objective-C,但是iOS入门用的是Swift,在这里要说的GCD也用Swift版的。Objective-C的就不详细说了,可转到唐巧的[[使用GCD](http://blog.devtang.com/2012/02/22/use-gcd/)]。 ## 在Swift上的GCD 在Swift上,GCD被封装成`DispatchObject`了,我们使用的是`DispatchObject`的子类,例如:`DispatchQueue`、`DispatchGroup`、`DispatchTime`··· 使用方法也变了,Objective-C将队列做参数传递,Swift需要先获取队列,然后再进行相关操作,比Objective-C用起来方便。 > [一个与代理、协议有关的类](http://blog.07coding.com/iOS/45.html)这篇文章也有用过GCD 常用的估计就下面这些了: ```swift DispatchQueue.global().async { } DispatchQueue.main.async { } //延时执行的时间需要用DispatchTime,首先DispatchTime.now()获取当前时间,然后再加上要延时的时间,单位是秒,Double类型。 DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) { } ``` 上面只使用了队列,下面说一下GCD的group吧。 `DispatchGroup`的应用场景就是某一步操作依赖多个并发操作,例如:上传身份证正反两面的照片,都上传成功后上报图片地址给服务器,这里就可以使用GCD分组并发上传了。思路是首先定义一个分组,然后并发的发起上传操作,使用group的`enter`和`leave`方法来标记各个并发请求,并发都处理完之后就会调用通过group的`notify`设置的闭包(我认为这就是个堆栈,enter就是push,leave则pop,然后group内部监控栈内的元素数量,当栈空了的时候就调用`notify`)。 下面是代码:(使用两个GET网络请求模拟上传文件的操作了) ```swift let group = DispatchGroup() group.enter() SessionManager.default.request("https://design.07coding.com/gcd/index/group?content=10000&no=1").responseJSON(completionHandler: { (respons) in log.debug(respons.result.value) log.debug(1) group.leave() }) group.enter() SessionManager.default.request("https://design.07coding.com/gcd/index/group?content=10000&no=2").responseJSON(completionHandler: { (respons) in log.debug(respons.result.value) group.leave() log.debug(2) }) group.notify(queue: DispatchQueue.global()) { log.debug("上传成功") } ``` 上面这部分代码没有判断网络请求的结果了,判断结果的处理方法是将这段代码封装成函数,在这个函数的所有者定义一个字典保存上传结果,在发起上传操作之前判断字典里对应的key的值,如果为nil就上传,上传成功之后就把图片的地址保存在字典里,当上传操作都完成后判断字典里的内容,如果不是所有都成功就再次调用这段代码所封装的函数。 > 网络请求:[Alamofire](https://github.com/Alamofire/Alamofire)
没有评论