GCD属于系统及的线程管理,功能很强大,比上两次我们分享的Operation
要强大。有不少老前辈们已经创造了很是很是多的资料介绍GCD,由于你们都是把GCD放在了多线程内容分享的最开始,因此致使好多好多理论知识都被放在了GCD部分。git
哈哈~幸亏非典型技术宅英明神武的错峰出行,把一些基础概念放在了上两篇文章里面。极大的减轻了这篇文章的阅读负担。github
既然前人都早了辣么多轮子,俺就不想再多介绍一些基础理论知识了。反正码再多的字,只会让你们马上立刻关掉这篇文章。并且上一篇关于Operation的阅读量就明显不高,看来你们不喜欢看啊。。。面试
那就容我偷偷懒嘛~重点仍是分享一些代码吧。bash
不是说理论知识不重要啊,面试全都问这个。并且理论知识直接影响到对技术的理解深度,决定能在这条路上走多远。是会成为某个领域的大牛,仍是只是简单的应用者。网络
纳尼?不是说不说基本概念了吗?easy~easy~easy~~~只介绍一些那些最最重要的,不了解就会影响到阅读这篇文章的内容啦。多线程
其实GCD和Operation不少地方惊人的类似。废话,都是多线程,底层都差很少,能不类似嘛!并发
GCD使用只须要两步:异步
。。。。。。~!@#¥%……&*¥%#@!~@#¥%…… 把大象放进冰箱里须要几步?!两步!打开冰箱门,把大象放进去!宅胖,如今很想抽死你啊!async
确实真的就是这样的。心里OS:这只是为了骗你入门,让你以为好简单。ui
上面说了任务,任务只有两种方式:同步、异步。
asynchronous
)具有开启新线程的能力,也具有跳过当前代码继续往下执行的能力。synchronous
)不具有开启新线程的能力,也不具有跳过当前代码继续往下执行的能力。名称 | 开启新线程的能力 | 跳过当前代码继续往下执行的能力 |
---|---|---|
异步 | 有 | 有 |
同步 | NULL |
NULL |
换句话简单的说,异步任务就是能够同时开启多个跑道,同时跑好多辆车。同步就是只有一条车道,堵死也飞不过去,只能乖乖的等着,一辆接一辆。
任务放入到队列里面,会遵循first in first out原则。举个恶心的例子,就像是拉屎,先吃先拉,后吃后拉。 哈哈~看了这个比方,别打死我~
队列呐,也只有两种:串行队列(Serial Dispatch Queue
)、并发队列(Concurrent Dispatch Queue
)。
串行队列(Serial Dispatch Queue
): 让任务一个接着一个有序的执行,一个任务执行完毕后,再执行下一个任务。
并发队列(Concurrent Dispatch Queue
) 可让多个任务同时执行,自动开启多个线程同时执行多个任务。
咦?有点晕,怎么感受跟刚才的任务分类同样呐?没错!就是这样的。
下面为了让你们不要晕菜,咱们把队列这个中文名字统一都叫作
Queue
,这样就和OperationQueue
对应起来了,就不会那么晕了。
Serial Queue
和Concurrent Queue
各自都有一个特殊的Queue
。
主队列(main queue
):是Serial Queue
中特殊的一种。只能在主线程中进行,而且主队列里面的任务,只有当主线程空闲的时候才能被执行。用来刷新UI使用。
全局队列(global queue
):是Concurrent Queue
中特殊的一种。用来执行耗时操做。
同时,GCD里面还能够自定义Queue。
最开始的时候,我们是否是说了,使用GCD就只有两步:建立任务,把任务放进Queue
里。
任务有两种:同步、异步。Queue
加上两种特殊的(不包括自定义的)一共有四种。来吧,开始排列组合吧。有八种吧。
名称 | 可以开启新线程 | 可以跳过当前代码继续进行 |
---|---|---|
异步 | 能 | 能 |
同步 | / | / |
Queue |
串行队列Serial | 并行队列concurrent | 主队列main | 全局队列global |
---|---|---|---|---|
可以多个任务同时执行 | / | 能 | / | 能 |
哈哈哈O(∩_∩)O哈哈~😆😆😆😆
完全晕菜😓
oooO ↘┏━┓ ↙ Oooo ( 踩)→┃你┃ ←(死 ) \ ( →┃√┃ ← ) / _)↗┗━┛ ↖(_/
来吧,直接告诉你结论吧。里面有几个特例。
☺ | 串行队列Serial Queue |
并行队列concurrent Queue |
主队列main Queue |
全局队列global Queue |
---|---|---|---|---|
异步 | 新线程、串行执行 | 新线程、并行执行 | 无新线程、串行执行 | 新线程、并行执行 |
同步 | 无新线程、串行执行 | 无新线程、串行执行 | 无新线程、串行执行 |
看上面这个表,因此若是想要同时作事情,固然不能选同步任务啦。由于它彻底没能力!搞很差还会形成锁死。
要想同时作事情,就选concurrent Queue
+ 异步,或者global Queue
+ 异步。 不过人家global Queue
原本就是concurrent Queue
特殊的一种。
若是有多任务,工做中最最省事儿经常使用的就是global Queue
+ 异步。单任务、刷新UI就用main Queue
+ 异步。
上面都没心思看也不要紧。工做中,若是有多任务,首选
global Queue
+ 异步。单任务、刷新UI就用main Queue
+ 异步。
我滴妈妈~通过上面的分析,最后,最基础的使用就两种了。 多任务:global Queue
+ 异步。 单任务、刷新UI就用main Queue
+ 异步。
说实话,我也是第一次这么大胆的简化。会不会被大神们拍死?坐等~~~~
global Queue
+ 异步任务/// global Queue + 异步任务
@IBAction func globalAsyn(_ sender: Any) {
//建立一个全局队列。
//get a global queue
let globalQueue = DispatchQueue.global()
for i in 0...10 {
//使用全局队列,开启异步任务。
//use the global queue , run in asynchronous
globalQueue.async {
print("I am No.\(i), current thread name is:\(Thread.current)")
}
}
}
复制代码
咱们看一下运行的结果,乱序打印的,而且没有在主线程中。这证实了确实是多个任务没有按照顺序执行。
main Queue
+ 异步任务/// main Queue + 异步任务
@IBAction func mainAsyn(_ sender: Any) {
//建立一个主队列
//get a main queue
let mainQueue = DispatchQueue.main
for i in 0...10 {
//使用主队列,开启异步任务
//use the main queue, run in asynchronous
mainQueue.async {
print("I am No.\(i), current thread name is:\(Thread.current)")
}
}
}
复制代码
需求:异步下载一张图片,下载完成后显示在UI界面
实现后的效果图:
思路:
global Queue
+异步,用来下载图片。由于过程可能很耗时。main Queue
+异步,把下载的图片赋值,刷新UI。这个小Demo其实也实现了线程间通信。
@IBAction func asynDownloadImage(_ sender: Any) {
let imageVC = ImageVC()
DispatchQueue.global().async {
if let url = URL.init(string: "https://placebeard.it/355/140") {
do {
let imageData = try Data(contentsOf: url)
let image = UIImage(data: imageData)
//由于宅胖家网络很好,为了模拟网络很耗时,就用了延时加载。
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.seconds(2), execute: {
imageVC.imageView.image = image
imageVC.imageView .sizeToFit()
})
} catch {
print(error)
}
}
}
navigationController?.pushViewController(imageVC, animated: true)
}
复制代码
DispatchQoS.QoSClass
是在Swift中封装的关于描述服务质量的类。
这个在Operation
里面也见到过,级别越高,就会给分配的资源越多。可是并非严格按照级别的高低来执行的。
这是一个枚举值:
public enum QoSClass {
case background //后台默默执行,The background quality of service class.
case utility //通用的,The utility quality of service class.
case `default` //默认值,The default quality of service class.
case userInitiated //用户发起的,The user-initiated quality of service class.
case userInteractive //用来执行用户交互,The user-interactive quality of service class.
case unspecified //没啥重要事情,The absence of a quality of service class.
public init?(rawValue: qos_class_t)
public var rawValue: qos_class_t { get }
}
复制代码
看到上面的枚举值,也大概能猜出来优先级的高低了。和界面相关的、用户的确定是高的,后台默默执行的确定是低的。
从高到低的顺序分别是:userInteractive
-> userInitiated
-> default
-> utility
-> background
-> unspecified
最基本的基础基本上就到这里了。掂量了一下,还有调度组、信号量、阻塞等等都还没写。这时候发现一篇写完GCD基础貌似不太现实,又不想一篇文章过长,那就拆开吧。下次再说。
最后,全部的代码都放在这里了:gitHub 下载后给颗Star吧~ 么么哒~(~o ̄3 ̄)~ 爱大家~
祝各位新春快乐~!~!