Dispatch — 基本介绍

基本介绍

This article is extracted from the chat log with AI. Please identify it with caution.

Apple 的 Dispatch 框架(也称为 Grand Central Dispatch,简称 GCD)是 macOS、iOS、watchOS 和 tvOS 上用于实现 多线程并发编程的核心技术之一。它提供了一个强大而高效的机制,用于在多核设备上调度任务,从而充分利用系统资源。


核心目标 #

GCD 的目标是:

  • 提高应用程序的响应速度和性能

  • 自动管理线程的生命周期,避免手动创建和销毁线程的复杂性

  • 提供线程安全的数据访问和调度控制


基本概念 #

1. 任务(Task) #

GCD 中的任务通常是一个闭包(closure)或函数,是你希望在后台执行的操作,例如下载、计算或更新 UI。

2. 队列(Dispatch Queue) #

GCD 使用队列调度任务。主要有两种:

  • 串行队列(Serial Queue):每次只执行一个任务,任务按顺序执行。

  • 并发队列(Concurrent Queue):可以同时执行多个任务,但仍按加入顺序开始。

GCD 会负责在线程池中调度这些任务。


常见 API #

创建队列 #

let serialQueue = DispatchQueue(label: "com.example.serial")
let concurrentQueue = DispatchQueue(label: "com.example.concurrent", attributes: .concurrent)

异步执行任务 #

DispatchQueue.global().async {
    // 后台线程执行耗时任务
    DispatchQueue.main.async {
        // 回到主线程更新 UI
    }
}

延时执行 #

DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
    print("2 秒后执行")
}

同步执行(⚠️ 警慎使用) #

DispatchQueue.main.sync {
    // 同步任务,会阻塞当前线程
}

系统提供的全局队列 #

DispatchQueue.global(qos: .background) // 最低优先级
DispatchQueue.global(qos: .userInitiated) // 用户发起的任务
DispatchQueue.main // 主线程队列,用于 UI 更新

常用 QoS(Quality of Service):

  • .userInteractive:立即响应用户(如滑动、动画)

  • .userInitiated:用户请求并希望尽快完成(如打开文档)

  • .utility:较长时间的后台任务(如下载、处理)

  • .background:不影响用户体验的任务(如预加载)


进阶特性 #

1. DispatchGroup #

用于追踪多个异步任务的完成情况。

let group = DispatchGroup()

queue.async(group: group) {
    // 任务 A
}
queue.async(group: group) {
    // 任务 B
}
group.notify(queue: .main) {
    print("所有任务完成")
}

2. DispatchSemaphore #

用于线程同步控制,控制并发数或资源访问。

3. DispatchWorkItem #

可取消或重复执行的任务单元。


GCD vs OperationQueue #

特性GCD(Dispatch)OperationQueue
编程风格函数式,闭包为主面向对象,支持继承和依赖
任务依赖不支持支持任务之间的依赖关系
任务取消基本不支持支持取消操作
灵活度简洁但不易扩展更适合复杂调度需求

小结 #

Dispatch 框架(GCD) 是 Apple 提供的轻量级并发工具,适合大多数场景下的并发处理,特别是 UI 和后台任务的调度。它的优势在于:

  • 简洁的 API

  • 高性能调度

  • 自动线程管理

在需要更复杂的任务控制时,可以考虑使用 OperationQueue 或 Swift 的 async/await 特性(iOS 13+/15+)。

示例 #

以下是一个 使用 GCD 实现图片下载并更新 UI 的完整 SwiftUI 示例,适合入门理解 GCD 的实战应用:


示例:使用 GCD 异步下载图片并在主线程更新 UI #

import SwiftUI

struct ContentView: View {
    @State private var image: UIImage? = nil
    @State private var isLoading = false

    let imageURL = URL(string: "https://picsum.photos/300")!

    var body: some View {
        VStack(spacing: 20) {
            if let image = image {
                Image(uiImage: image)
                    .resizable()
                    .scaledToFit()
                    .frame(height: 300)
            } else {
                Rectangle()
                    .fill(Color.gray.opacity(0.3))
                    .frame(height: 300)
                    .overlay(Text("No Image"))
            }

            if isLoading {
                ProgressView()
            }

            Button("下载图片") {
                downloadImage()
            }
        }
        .padding()
    }

    func downloadImage() {
        isLoading = true

        // 在后台线程下载图片
        DispatchQueue.global(qos: .userInitiated).async {
            if let data = try? Data(contentsOf: imageURL),
               let downloadedImage = UIImage(data: data) {
                // 下载成功后,在主线程更新 UI
                DispatchQueue.main.async {
                    self.image = downloadedImage
                    self.isLoading = false
                }
            } else {
                // 下载失败,也需要在主线程更新状态
                DispatchQueue.main.async {
                    self.isLoading = false
                }
            }
        }
    }
}

要点解释 #

  • DispatchQueue.global(qos: .userInitiated).async {}
    → 在后台线程中执行耗时的下载任务。

  • DispatchQueue.main.async {}
    → 下载完成后回到主线程更新 @State,从而刷新 UI。

  • @State
    → SwiftUI 的状态变量,驱动界面变化。


这个例子清楚地展示了 GCD 在实际应用中的核心流程:将耗时任务放到后台线程执行,完成后在主线程安全更新界面。这种模式是处理网络请求、文件 IO、数据库操作等常见异步任务的基本范式。

本文共 1365 字,创建于 Jun 8, 2025
相关标签: Xcode, ByAI