iOS开发技术栈:多线程

本文详细介绍了iOS开发中几种重要的线程管理与并发执行技术,包括基础的NSThread,面向对象的NSOperation和NSOperationQueue,低级别并发的GrandCentralDispatch,以及管理事件的RunLoop。通过实例展示了如何使用这些工具进行任务调度和线程控制。
摘要由CSDN通过智能技术生成

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

  • 17
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值