NSThread
NSThread 是最基本的线程操作类。它提供了创建和管理线程的方法,允许你直接控制线程的生命周期。使用 NSThread,你可以创建一个新线程,并分配一个任务让它在后台执行。这种方式给予了开发者很高的控制度,但相应地,也需要开发者负责线程的管理,比如创建、启动、同步和销毁等。它比较适用于某些需要精细控制线程行为的场景。
import Foundation
class MyThreadedClass {
// 该方法将在新线程中执行
@objc func threadedFunction() {
// 输出当前线程信息
print("Threaded function is running on: \(Thread.current)")
// 执行一些后台任务
for i in 0..<5 {
print("Threaded task \(i)")
sleep(1) // 模拟耗时操作
}
}
// 创建并启动线程
func startThread() {
let thread = Thread(target: self, selector: #selector(threadedFunction), object: nil)
thread.start() // 开始线程的执行
}
}
// 使用方法
let myInstance = MyThreadedClass()
myInstance.startThread() // 调用该方法后,threadedFunction 将在新线程中运行
首先定义了一个含有 threadedFunction
方法的类 MyThreadedClass
。这个方法被标记为 @objc
,因为它会被 NSThread
通过 Objective-C 的运行时来调用。随后,在 startThread
方法中创建了一个 NSThread
对象,将 threadedFunction
设置为线程执行的目标函数,并调用 start()
来启动线程。
当你运行 startThread()
方法时,threadedFunction
会在一个新的后台线程上执行,主线程会继续执行其他任务,因此不会被阻塞。在 threadedFunction
中,我们通过一个简单的循环模拟了一个耗时任务。这个循环将打印出几个信息,并在每次迭代中暂停一秒钟。
NSOperation 和 NSOperationQueue
NSOperation 和 NSOperationQueue 是更高级别的抽象,提供了面向对象的方式来定义你的任务 (NSOperation),然后将这些任务添加到队列 (NSOperationQueue) 中以并发或串行的方式执行。NSOperation 本质上是一个抽象类,你通常会通过继承 NSOperation 来定义具体的操作或者使用它的子类如 NSBlockOperation。NSOperationQueue 管理一个或多个 NSOperation 对象的执行。使用这种方式可以很容易地添加任务依赖、设置最大并发操作数、以及取消或暂停任务等。它提供了比 NSThread 更高级的抽象,允许开发者更容易地管理任务。
import Foundation
// 创建自定义 NSOperation
class MyOperation: Operation {
let operationId: Int
init(id: Int) {
operationId = id
}
override func main() {
if isCancelled {
return
}
print("Operation \(operationId) is starting")
// 模拟耗时操作
Thread.sleep(forTimeInterval: 2)
if isCancelled {
return
}
print("Operation \(operationId) has finished")
}
}
// 创建 OperationQueue
let queue = OperationQueue()
// 设置最大并发操作数,比如这里设置为2
queue.maxConcurrentOperationCount = 2
// 创建多个 Operation 实例并添加至队列
for i in 1...5 {
let myOperation = MyOperation(id: i)
queue.addOperation(myOperation)
}
// 添加操作之间的依赖关系(可选)
// 例如,operation2 可以依赖于 operation1 的完成
let operation1 = MyOperation(id: 1)
let operation2 = MyOperation(id: 2)
operation2.addDependency(operation1)
// 将具有依赖关系的操作添加到队列
queue.addOperation(operation1)
queue.addOperation(operation2)
// 使用 BlockOperation 添加 block 到队列
let blockOperation = BlockOperation {
print("Block operation is executing")
}
queue.addOperation(blockOperation)
// 注:此代码演示了同时使用自定义 Operation 和 BlockOperation,实践中通常选其一。
Grand Central Dispatch (GCD)
Grand Central Dispatch (GCD) 是一个强大的低级别的并发执行机制,它可以用来执行任务并发或串行地在后台执行。GCD 自动管理线程池,以优化的方式来执行任务。在 iOS 开发中,GCD 是处理并行任务的首选方式,特别是对于那些不需要与 UI 交互的数据处理或计算密集型任务。GCD 的核心概念包括队列(串行队列和并发队列)和任务(使用 block 定义的工作单元)。GCD 提供了简单的 API 来实现复杂的多线程操作。
import Foundation
// 获取全局并发队列
let globalQueue = DispatchQueue.global()
// 将任务异步添加到全局并发队列
globalQueue.async {
print("Doing some work on global concurrent queue.")
// 模拟耗时任务
Thread.sleep(forTimeInterval: 2)
print("Global concurrent queue work done.")
}
// 创建自定义串行队列
let serialQueue = DispatchQueue(label: "com.example.mySerialQueue")
// 将任务异步添加到串行队列
serialQueue.async {
print("Doing some work on my serial queue.")
// 模拟耗时任务
Thread.sleep(forTimeInterval: 2)
print("My serial queue work done.")
}
// 主队列
let mainQueue = DispatchQueue.main
// 异步将任务添加到主队列
mainQueue.async {
// 更新 UI 等操作
print("Update UI on main queue.")
}
// 延迟执行
let delayInSeconds = 2.0
DispatchQueue.main.asyncAfter(deadline: .now() + delayInSeconds) {
// 延迟2秒后执行的代码
print("Delayed operation on main queue.")
}
// 使用 DispatchGroup 管理一组任务
let dispatchGroup = DispatchGroup()
globalQueue.async(group: dispatchGroup) {
print("Task 1 started.")
// 模拟耗时任务
Thread.sleep(forTimeInterval: 1)
print("Task 1 finished.")
}
globalQueue.async(group: dispatchGroup) {
print("Task 2 started.")
// 模拟耗时任务
Thread.sleep(forTimeInterval: 2)
print("Task 2 finished.")
}
// 当所有任务完成时收到通知
dispatchGroup.notify(queue: DispatchQueue.main) {
print("All tasks in the group finished.")
}
RunLoop
RunLoop 是用来管理事件的循环,每个线程都有自己的 RunLoop,但它默认不会启动。RunLoop 能管理其输入源(比如 UI事件、定时器事件或其他系统事件)并在有事件时唤醒线程处理。在 iOS 开发中,主线程的 RunLoop 会自动运行,用于处理 UI 更新、事件响应等。RunLoop 对于管理线程的执行时间、处理定时器事件、以及实现线程间通信非常重要,但在实现上比较复杂,需要深入理解其运行机制。
import Foundation
// 创建定时器
let timer = Timer(timeInterval: 1.0, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
// 获取当前线程的 RunLoop,并将定时器添加到默认模式
RunLoop.current.add(timer, forMode: .default)
// 定义定时器触发时执行的方法
@objc func timerAction() {
print("Timer tick")
}
// 启动RunLoop(在子线程中,主线程的 RunLoop 自动运行)
RunLoop.current.run()
在这个 Swift 示例中,我们假定这段代码在一个 NSObject
子类的上下文中,因为我们使用 @objc
属性来表示 timerAction
是可以被 Timer
调用的 Objective-C 方法。
这段代码首先创建了一个 Timer
对象,其构造函数指定了每秒触发一次,目标对象是 self
(当前对象),选择器是 timerAction
方法,没有用户信息,而且是重复的。然后,获取当前线程的 RunLoop
并将定时器添加到该 RunLoop
的默认模式下。这样,当 RunLoop
运行时,它将定期触发 timerAction
方法。
在这里调用了 RunLoop.current.run()
来启动当前线程的 RunLoop
。在实际应用中,如果你在子线程中创建 RunLoop
,需要像这样手动启动它。主线程的 RunLoop
由应用程序主框架自动处理,你通常不需要(也不应该)在主线程中手动启动或停止 RunLoop
。