第7章 多线程与并发
在iOS开发中,多线程与并发是提升应用性能和用户体验的关键技术。通过合理利用多线程,我们可以在后台执行耗时操作(如网络请求、数据处理)而不影响主线程的响应性。本章将详细介绍iOS中的多线程与并发技术,包括GCD(Grand Central Dispatch)、OperationQueue以及线程安全与同步。
7.1 GCD基础
7.1.1 什么是GCD?
GCD(Grand Central Dispatch)是苹果提供的一个并发处理框架,旨在简化多线程编程的复杂性。通过GCD,开发者可以轻松地在不同线程上执行任务,而无需手动管理线程的创建和销毁。
7.1.2 GCD的核心概念
1. 队列(Queue)
队列是任务的执行序列。GCD提供了两种类型的队列:
- 主队列(Main Queue):用于更新UI或执行需要在主线程完成的任务。
- 全局队列(Global Queue):用于执行后台任务,支持多线程。
- 自定义队列(Custom Queue):开发者可以根据需求创建自己的队列。
2. 任务(Task)
任务是队列中需要执行的代码块。任务可以是同步或异步的。
3. 同步与异步
- 同步(Synchronous):任务在当前线程执行,当前线程会等待任务完成。
- 异步(Asynchronous):任务在队列中执行,当前线程不会等待任务完成。
7.1.3 示例:使用GCD执行任务
// 创建一个全球队列
let globalQueue = DispatchQueue.global(qos: .background)
// 异步执行任务
globalQueue.async {
// 执行耗时操作
print("后台任务执行完成")
// 在主线程更新UI
DispatchQueue.main.async {
print("UI更新完成")
}
}
通过上面的代码,我们创建了一个全局队列,并在队列中异步执行了一个耗时任务。完成后,我们又在主线程中更新了UI。
7.2 OperationQueue
OperationQueue是iOS中另一个强大的并发执行工具。它与GCD类似,但提供了更多的灵活性和可管理性。
7.2.1 什么是OperationQueue?
OperationQueue用于管理和执行Operation
对象。每个Operation
代表一个任务,可以通过将任务添加到OperationQueue
中来实现并发执行。
7.2.2 OperationQueue的核心概念
1. 并行与串行队列
- 并行队列(Concurrent Queue):允许同时执行多个任务。
- 串行队列(Serial Queue):任务按顺序执行。
2. 最大并行度(Max Concurrency)
通过设置maxConcurrentOperationCount
,可以控制队列中同时执行的任务数量。
3. 依赖关系(Dependency)
可以设置任务之间的依赖关系,确保某些任务在其他任务完成后执行。
7.2.3 示例:使用OperationQueue执行任务
// 创建一个并行队列
let operationQueue = OperationQueue()
operationQueue.maxConcurrentOperationCount = 2
// 创建任务
let operation1 = BlockOperation {
print("任务1执行中...")
}
let operation2 = BlockOperation {
print("任务2执行中...")
}
// 添加任务 到队列
operationQueue.addOperation(operation1)
operationQueue.addOperation(operation2)
通过上面的代码,我们创建了一个最大并行度为2的并行队列,并在队列中添加了两个任务。任务会同时执行。
7.3 线程安全与同步
7.3.1 什么是线程安全?
线程安全指的是多个线程可以安全地访问共享资源(如变量、数组等)而不导致数据损坏或竞态条件(Race Condition)。线程不安全的问题可能会导致程序崩溃或数据错误。
7.3.2 线程安全的常见问题
1. 共享资源的修改
当多个线程同时修改一个共享资源时,可能会导致数据竞争问题。
2. 异步操作中的UI更新
UI操作必须在主线程执行,否则会导致崩溃或不一致的UI状态。
7.3.3 线程安全的同步方法
1. 互斥锁(Mutex)
通过互斥锁可 以确保同一时间只有一个线程访问共享资源。
2. 信号量(Semaphore)
信号量用于控制对共享资源的访问权限。
3. GCD的同步队列
let sharedArray =NSMutableArray()
let queue = DispatchQueue(label: "同步队列")
// 异步执行任务
queue.async {
sharedArray.add("任务1")
}
// 同步执行任务
queue.sync {
sharedArray.add("任务2")
}
通过上面的代码,我们确保对sharedArray
的操作是线程安全的。
7.4 综合案例:下载图片并显示在UIImageView中
class ViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var downloadButton: UIButton!
let downloadQueue = DispatchQueue.global(qos: .background)
func downloadImage(from url: String) {
downloadQueue.async {
// 模拟下载操作
Thread.sleep(forTimeInterval: 2)
// 在主线程更新UI
DispatchQueue.main.async {
self.imageView.image = UIImage(named: "example_image")
self.downloadButton.isEnabled = true
self.downloadButton.setTitle("重新下载", for: .normal)
}
}
}
@IBAction func downloadButtonTapped(_ sender: UIButton) {
downloadButton.isEnabled = false
downloadButton.setTitle("下载中...", for: .normal)
downloadImage(from: "https://example.com/image.jpg")
}
}
通过上面的代码,我们在后台队列中执行图片下载操作,并在下载完成后回到主线程更新UI。
总结来说,掌握GCD、OperationQueue以及线程安全的技巧,可以帮助我们在iOS开发中更好地利用多线程与并发技术,提升应用性能和用户体验。