Swift多线程:使用GCD实现异步下载图片

GCD属于系统及的线程管理,功能很强大,比上两次咱们分享的Operation要强大。有很多老前辈们已经创造了非常非常多的资料介绍GCD,因为大家都是把GCD放在了多线程内容分享的最开始,所以导致好多好多理论知识都被放在了GCD部分。

哈哈~幸好非典型技术宅英明神武的错峰出行,把一些基础概念放在了上两篇文章里面。极大的减轻了这篇文章的阅读负担。

既然前人都早了辣么多轮子,俺就不想再多介绍一些基础理论知识了。反正码再多的字,只会让大家立刻马上关掉这篇文章。而且上一篇关于Operation的阅读量就明显不高,看来大家不喜欢看啊。。。

那就容我偷偷懒嘛~重点还是分享一些代码吧。

不是说理论知识不重要啊,面试全都问这个。而且理论知识直接影响到对技术的理解深度,决定能在这条路上走多远。是会成为某个领域的大牛,还是只是简单的应用者。

1. GCD基础知识

纳尼?不是说不说基本概念了吗?easyeasyeasy~~只介绍一些那些最最重要的,不了解就会影响到阅读这篇文章的内容啦。

其实GCD和Operation很多地方惊人的相似。废话,都是多线程,底层都差不多,能不相似嘛!

GCD使用只需要两步:

  • STEP ONE:创建任务。
  • STEP TWO:把任务放进队列里。

。。。。。。!@#¥%……&*¥%#@!@#¥%…… 把大象放进冰箱里需要几步?!两步!打开冰箱门,把大象放进去!宅胖,现在很想抽死你啊!

确实真的就是这样的这只是为了骗你入门,让你觉得好简单

1.1 任务的分类

上面说了任务,任务只有两种方式:同步、异步。

  • 异步(asynchronous)具备开启新线程的能力,也具备跳过当前代码继续往下执行的能力。
  • 同步(synchronous)不具备开启新线程的能力,也不具备跳过当前代码继续往下执行的能力。
名称 开启新线程的能力 跳过当前代码继续往下执行的能力
异步
同步 NULL NULL

换句话简单的说,异步任务就是可以同时开启多个跑道,同时跑好多辆车。同步就是只有一条车道,堵死也飞不过去,只能乖乖的等着,一辆接一辆。

任务放入到队列里面,会遵循first in first out原则。举个恶心的例子,就像是拉屎,先吃先拉,后吃后拉。
哈哈看了这个比方,别打死我

image.png

1.2 队列的分类

队列呐,也只有两种:串行队列(Serial Dispatch Queue)、并发队列(Concurrent Dispatch Queue)。

  • 串行队列(Serial Dispatch Queue):
    让任务一个接着一个有序的执行,一个任务执行完毕后,再执行下一个任务。

  • 并发队列(Concurrent Dispatch Queue
    可以让多个任务同时执行,自动开启多个线程同时执行多个任务。

咦?有点晕,怎么感觉跟刚才的任务分类一样呐?没错!就是这样的。

下面为了让大家不要晕菜,我们把队列这个中文名字统一都叫做Queue,这样就和OperationQueue对应起来了,就不会那么晕了。

Serial QueueConcurrent Queue各自都有一个特殊的Queue

主队列(main queue):是Serial Queue中特殊的一种。只能在主线程中进行,并且主队列里面的任务,只有当主线程空闲的时候才能被执行。用来刷新UI使用。

全局队列(global queue):是Concurrent Queue中特殊的一种。用来执行耗时操作。

同时,GCD里面还可以自定义Queue。

1.3 排列组合开始

最开始的时候,咱们是不是说了,使用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 + 异步。

2. GCD的基础应用

我滴妈妈~经过上面的分析,最后,最基础的使用就两种了。
多任务:global Queue + 异步。
单任务、刷新UI就用main Queue + 异步。

说实话,我也是第一次这么大胆的简化。会不会被大神们拍死?坐等~~~~

2.1 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)")
        }
    }
}
image.png

我们看一下运行的结果,乱序打印的,并且没有在主线程中。这证明了确实是多个任务没有按照顺序执行。

2.2 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)")
            
        }
    }
}
image.png

我们看一下运行的结果,确实是顺序打印的。并且都执行在了主线程中。

2.3 小实践:实现异步下载图片

需求:异步下载一张图片,下载完成后显示在UI界面

实现后的效果图:

GCD.gif

思路:

  1. 在当前UI动作之外,开启一个global Queue+异步,用来下载图片。因为过程可能很耗时。
  2. 等下载完成后,开启一个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)

}

3. GCD的服务质量(优先级)

DispatchQoS.QoSClass是在Swift中封装的关于描述服务质量的类。

这个在Operation里面也见到过,级别越高,就会给分配的资源越多。但是并不是严格按照级别的高低来执行的

image.png

这是一个枚举值:

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 ̄)~ 爱你们~


iOS多线程系列之一:Operation基础操作,按优先级加载图片
iOS多线程系列之二:Operation实例,异步加载CollectionView图片
iOS多线程系列之三:使用GCD实现异步下载图片
iOS多线程系列之四:GCD进阶,单例、信号量、任务组
iOS多线程系列之五:使用Thread进行多线程间通讯,协调子线程任务

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容