多线程
在之前我们提到,整个列表的数据都是从网络中请求加载到cell当中的,但是由于cell中含有图像的加载的问题,会造成我们App的启动速度十分缓慢和我们在滑动列表的时候产生严重的卡顿,所以接下来我们需要利用线程对列表的滑动体验进行优化。
优化前的效果
线程是什么
线程是某一进程中一个单独运行的程序。也就是进程的一个实体,是CPU调度和分派的基本单位。
我们如何使用线程
在iOS中,线程通常被分为主线程和其他线程。通常我们编写的代码都是在主线程中运行的。为了优化体验,我们需要将图片的加载过程放入到其他线程中,并且在Cell中使用占位图,在非主线程中请求图片数据并加载到Cell上。
let downloadImageThread = Thread(block: { [self] in
do {
rightImage.image = UIImage(data: try Data(contentsOf: URL(string: model.thumbnail_pic_s)!))
} catch {
}
})
downloadImageThread.name = "downloadImageThread"
downloadImageThread.start()
在写下以上代码之后,可以发现无论是App的启动速度和列表的滑动体验都又了明显的提升。
效果如下
虽然我们提前放置了占位图,但是任何有关UI的操作都应该放在主线程中进行
所以我们在这里引入另外一个线程的管理方式
Grand Central Dispatch(GCD)
在了解GCD之前,我们需要在这里引入两个概念,任务和队列
- 任务:指的是我们需要执行的操作,也就是代码块(block)中的代码。
- 队列:指的是执行任务的等待队列,从数据结构中我们知道队列的特点是先进先出,所以我们的任务也是先进先出的。
GCD的优点就是,使开发者从面向线程较为底层的管理变成了面向队列,由系统来为队列从线程池中分配线程执行我们的任务。
将上述代码改成使用GCD的方式则如下所示
//全局并发队列
let downloadQueue = DispatchQueue.global(qos: .default)
let mainQueue = DispatchQueue.main
//在非主队列中进行网络请求
downloadQueue.async(execute: { [self] in
var modelImage: UIImage? = nil
do {
modelImage = UIImage(data: try Data(contentsOf: URL(string: model.thumbnail_pic_s)!))
} catch {
}
//在主队列中进行UI操作
mainQueue.async(execute: { [self] in
rightImage.image = modelImage
})
})