一、NSOperation 是什么?
NSOperation是基于GCD之上的更高一层封装,提供了更强大的任务管理能力,NSOperation需要配合NSOperationQueue来实现多线程。
1.核心概念
// GCD 的思维:执行一个闭包
DispatchQueue.global().async {
print("执行任务")
}
// NSOperation 的思维:创建一个任务对象
let operation = BlockOperation {
print("执行任务")
}
let queue = OperationQueue()
queue.addOperation(operation)
2.NSOperation vs GCD
GCD:
- 轻量级
- 简单快速
- 任务依赖需要手动实现
- 取消任务困难
NSOperation:
- 面向对象
- 功能强大
- 内置任务依赖
- 内置取消机制
- 可以暂停/恢复队列
- 支持 KVO
二、NSOperation 的类型
- BlockOperation(最常用)
// 创建 BlockOperation
let operation = BlockOperation {
print("执行任务")
sleep(1)
print("任务完成")
}
// 添加到队列
let queue = OperationQueue()
queue.addOperation(operation)
// 或者直接添加闭包
queue.addOperation {
print("直接添加任务")
}
- 自定义 Operation
class DownloadOperation: Operation {
let url: URL
var downloadedData: Data?
init(url: URL) {
self.url = url
super.init()
}
// 重写 main 方法
override func main() {
// 检查是否被取消
if isCancelled {
return
}
print("开始下载: \(url)")
// 模拟下载
sleep(2)
// 再次检查取消状态
if isCancelled {
print("下载被取消")
return
}
downloadedData = Data()
print("下载完成")
}
}
// 使用
let operation = DownloadOperation(url: URL(string: "https://example.com")!)
let queue = OperationQueue()
queue.addOperation(operation)
三、OperationQueue(操作队列)
- 创建队列
// 创建队列
let queue = OperationQueue()
// 设置队列名称
queue.name = "com.example.myqueue"
// 设置最大并发数
queue.maxConcurrentOperationCount = 3 // 最多3个任务同时执行
// 串行队列
queue.maxConcurrentOperationCount = 1
// 并发队列(默认)
queue.maxConcurrentOperationCount = OperationQueue.defaultMaxConcurrentOperationCount
// 主队列
let mainQueue = OperationQueue.main
- 添加任务
let queue = OperationQueue()
// 方式1:添加 Operation 对象
let operation = BlockOperation {
print("任务1")
}
queue.addOperation(operation)
// 方式2:直接添加闭包
queue.addOperation {
print("任务2")
}
// 方式3:批量添加
let op1 = BlockOperation { print("任务3") }
let op2 = BlockOperation { print("任务4") }
let op3 = BlockOperation { print("任务5") }
queue.addOperations([op1, op2, op3], waitUntilFinished: false)
// 方式4:等待完成
queue.addOperations([op1, op2, op3], waitUntilFinished: true)
print("所有任务完成")
四、任务依赖(核心功能)
- 基本依赖
let queue = OperationQueue()
// 创建三个任务
let downloadOp = BlockOperation {
print("1. 下载图片")
sleep(2)
}
let filterOp = BlockOperation {
print("2. 应用滤镜")
sleep(1)
}
let uploadOp = BlockOperation {
print("3. 上传图片")
sleep(1)
}
// 设置依赖关系
filterOp.addDependency(downloadOp) // 滤镜依赖下载
uploadOp.addDependency(filterOp) // 上传依赖滤镜
// 添加到队列(顺序无关)
queue.addOperations([uploadOp, filterOp, downloadOp], waitUntilFinished: false)
// 输出:
// 1. 下载图片
// 2. 应用滤镜
// 3. 上传图片
- 复杂依赖
class DependencyExample {
let queue = OperationQueue()
func demonstrateComplexDependency() {
// 任务A:下载图片1
let downloadA = BlockOperation {
print("下载图片A")
sleep(2)
}
// 任务B:下载图片2
let downloadB = BlockOperation {
print("下载图片B")
sleep(2)
}
// 任务C:合并图片(依赖A和B)
let merge = BlockOperation {
print("合并图片")
sleep(1)
}
merge.addDependency(downloadA)
merge.addDependency(downloadB)
// 任务D:应用滤镜(依赖合并)
let filter = BlockOperation {
print("应用滤镜")
sleep(1)
}
filter.addDependency(merge)
// 任务E:上传(依赖滤镜)
let upload = BlockOperation {
print("上传图片")
sleep(1)
}
upload.addDependency(filter)
// 添加所有任务
queue.addOperations([upload, filter, merge, downloadB, downloadA], waitUntilFinished: false)
// 执行顺序:
// downloadA 和 downloadB 并发执行
// → merge
// → filter
// → upload
}
}
五、任务取消
- 基本取消
class CancellationExample {
func demonstrateCancel() {
let operation = BlockOperation {
for i in 1...10 {
// 检查取消状态
if Thread.current.isCancelled {
print("任务被取消")
return
}
print("执行步骤 \(i)")
sleep(1)
}
}
let queue = OperationQueue()
queue.addOperation(operation)
// 2秒后取消
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
operation.cancel()
print("已发送取消信号")
}
}
}
- 正确的取消模式
class DownloadOperation: Operation {
let url: URL
var downloadedData: Data?
init(url: URL) {
self.url = url
}
override func main() {
// 检查点1:开始前
guard !isCancelled else {
print("任务在开始前被取消")
return
}
print("开始下载")
// 模拟下载过程
for i in 1...10 {
// 检查点2:循环中
guard !isCancelled else {
print("下载在 \(i*10)% 时被取消")
return
}
print("下载进度: \(i*10)%")
sleep(1)
}
// 检查点3:完成前
guard !isCancelled else {
print("任务在完成前被取消")
return
}
downloadedData = Data()
print("下载完成")
}
}
// 使用
let operation = DownloadOperation(url: URL(string: "https://example.com")!)
let queue = OperationQueue()
queue.addOperation(operation)
// 5秒后取消
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
operation.cancel()
}
- 取消所有任务
let queue = OperationQueue()
// 添加多个任务
for i in 1...10 {
queue.addOperation {
print("任务 \(i) 开始")
sleep(2)
print("任务 \(i) 完成")
}
}
// 取消所有任务
queue.cancelAllOperations()
print("已取消所有任务")
六、任务状态
- 状态属性
let operation = BlockOperation {
print("执行任务")
sleep(2)
}
// 状态检查
print("isReady: \(operation.isReady)") // 是否准备好
print("isExecuting: \(operation.isExecuting)") // 是否正在执行
print("isFinished: \(operation.isFinished)") // 是否已完成
print("isCancelled: \(operation.isCancelled)") // 是否已取消
let queue = OperationQueue()
queue.addOperation(operation)
// 执行中
sleep(1)
print("isExecuting: \(operation.isExecuting)") // true
// 完成后
sleep(2)
print("isFinished: \(operation.isFinished)") // true
- 状态转换
Operation 的生命周期:
创建 → 准备 → 执行 → 完成
↓ ↓ ↓ ↓
isReady ✅ ❌ ❌
isExecuting ❌ ✅ ❌
isFinished ❌ ❌ ✅
取消可以在任何阶段发生:
isCancelled: ❌ → ✅
- KVO 监听状态
class OperationObserver: NSObject {
var operation: Operation?
func observeOperation(_ operation: Operation) {
self.operation = operation
// 监听状态变化
operation.addObserver(
self,
forKeyPath: "isFinished",
options: .new,
context: nil
)
operation.addObserver(
self,
forKeyPath: "isExecuting",
options: .new,
context: nil
)
}
override func observeValue(
forKeyPath keyPath: String?,
of object: Any?,
change: [NSKeyValueChangeKey : Any]?,
context: UnsafeMutableRawPointer?
) {
if keyPath == "isFinished" {
print("任务完成")
} else if keyPath == "isExecuting" {
print("任务开始执行")
}
}
deinit {
operation?.removeObserver(self, forKeyPath: "isFinished")
operation?.removeObserver(self, forKeyPath: "isExecuting")
}
}
七、完成回调
- completionBlock
let operation = BlockOperation {
print("执行任务")
sleep(2)
print("任务完成")
}
// 设置完成回调
operation.completionBlock = {
print("完成回调执行")
print("注意:这个回调可能在任何线程执行")
}
let queue = OperationQueue()
queue.addOperation(operation)
// 输出:
// 执行任务
// 任务完成
// 完成回调执行
- 链式任务
class ChainedOperations {
func demonstrateChain() {
let queue = OperationQueue()
// 任务1
let op1 = BlockOperation {
print("任务1执行")
sleep(1)
}
// 任务2
let op2 = BlockOperation {
print("任务2执行")
sleep(1)
}
// 任务3
let op3 = BlockOperation {
print("任务3执行")
sleep(1)
}
// 设置完成回调
op1.completionBlock = {
print("任务1完成")
}
op2.completionBlock = {
print("任务2完成")
}
op3.completionBlock = {
print("任务3完成")
print("所有任务完成")
}
// 设置依赖
op2.addDependency(op1)
op3.addDependency(op2)
// 添加到队列
queue.addOperations([op1, op2, op3], waitUntilFinished: false)
}
}
八、优先级
- 设置优先级
let queue = OperationQueue()
// 低优先级
let lowOp = BlockOperation {
print("低优先级任务")
}
lowOp.queuePriority = .veryLow
// 普通优先级
let normalOp = BlockOperation {
print("普通优先级任务")
}
normalOp.queuePriority = .normal
// 高优先级
let highOp = BlockOperation {
print("高优先级任务")
}
highOp.queuePriority = .veryHigh
// 添加到队列
queue.addOperations([lowOp, normalOp, highOp], waitUntilFinished: false)
// 输出顺序:高 → 普通 → 低
- 优先级级别
// 优先级从高到低:
operation.queuePriority = .veryHigh // 最高
operation.queuePriority = .high // 高
operation.queuePriority = .normal // 普通(默认)
operation.queuePriority = .low // 低
operation.queuePriority = .veryLow // 最低
- 服务质量(QoS)
let operation = BlockOperation {
print("执行任务")
}
// 设置服务质量
operation.qualityOfService = .userInteractive // 用户交互
operation.qualityOfService = .userInitiated // 用户发起
operation.qualityOfService = .utility // 实用工具
operation.qualityOfService = .background // 后台
let queue = OperationQueue()
queue.qualityOfService = .userInitiated // 队列级别的 QoS
queue.addOperation(operation)
九、队列控制
- 暂停和恢复
let queue = OperationQueue()
// 添加任务
for i in 1...10 {
queue.addOperation {
print("任务 \(i)")
sleep(1)
}
}
// 暂停队列
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
queue.isSuspended = true
print("队列已暂停")
}
// 恢复队列
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
queue.isSuspended = false
print("队列已恢复")
}
// 注意:暂停不会停止正在执行的任务
- 等待完成
let queue = OperationQueue()
// 添加任务
for i in 1...5 {
queue.addOperation {
print("任务 \(i)")
sleep(1)
}
}
// 等待所有任务完成(阻塞当前线程)
queue.waitUntilAllOperationsAreFinished()
print("所有任务完成")
- 获取队列信息
let queue = OperationQueue()
// 添加任务
for i in 1...10 {
queue.addOperation {
sleep(1)
}
}
// 获取队列信息
print("队列中的任务数: \(queue.operationCount)")
print("所有任务: \(queue.operations)")
print("是否暂停: \(queue.isSuspended)")
十、实战案例
案例1:批量图片下载
class ImageDownloader {
let downloadQueue = OperationQueue()
init() {
downloadQueue.maxConcurrentOperationCount = 3
downloadQueue.name = "ImageDownloadQueue"
}
func downloadImages(urls: [URL], completion: @escaping ([UIImage]) -> Void) {
var images: [UIImage] = []
let lock = NSLock()
// 创建下载任务
let downloadOperations = urls.map { url -> BlockOperation in
return BlockOperation {
if let image = self.downloadImage(from: url) {
lock.lock()
images.append(image)
lock.unlock()
}
}
}
// 创建完成任务
let completionOperation = BlockOperation {
DispatchQueue.main.async {
completion(images)
}
}
// 设置依赖
for op in downloadOperations {
completionOperation.addDependency(op)
}
// 添加所有任务
downloadQueue.addOperations(downloadOperations, waitUntilFinished: false)
downloadQueue.addOperation(completionOperation)
}
private func downloadImage(from url: URL) -> UIImage? {
print("下载: \(url)")
sleep(1)
return UIImage()
}
}
// 使用
let downloader = ImageDownloader()
let urls = (1...10).map { URL(string: "https://example.com/image\($0).jpg")! }
downloader.downloadImages(urls: urls) { images in
print("下载完成,共 \(images.count) 张图片")
}
案例2:图片处理流水线
class ImagePipeline {
let queue = OperationQueue()
func processImage(_ image: UIImage, completion: @escaping (UIImage?) -> Void) {
// 1. 下载操作
let downloadOp = BlockOperation {
print("1. 下载图片")
sleep(1)
}
// 2. 解码操作
let decodeOp = BlockOperation {
print("2. 解码图片")
sleep(1)
}
decodeOp.addDependency(downloadOp)
// 3. 调整大小
let resizeOp = BlockOperation {
print("3. 调整大小")
sleep(1)
}
resizeOp.addDependency(decodeOp)
// 4. 应用滤镜
let filterOp = BlockOperation {
print("4. 应用滤镜")
sleep(1)
}
filterOp.addDependency(resizeOp)
// 5. 压缩
let compressOp = BlockOperation {
print("5. 压缩图片")
sleep(1)
}
compressOp.addDependency(filterOp)
// 6. 完成
let completionOp = BlockOperation {
print("6. 处理完成")
DispatchQueue.main.async {
completion(image)
}
}
completionOp.addDependency(compressOp)
// 添加所有操作
queue.addOperations([
downloadOp,
decodeOp,
resizeOp,
filterOp,
compressOp,
completionOp
], waitUntilFinished: false)
}
}
// 使用
let pipeline = ImagePipeline()
pipeline.processImage(UIImage()) { processedImage in
print("图片处理完成")
}
案例3:可取消的搜索
class SearchManager {
let searchQueue = OperationQueue()
var currentSearchOperation: Operation?
init() {
searchQueue.maxConcurrentOperationCount = 1
}
func search(keyword: String, completion: @escaping ([String]) -> Void) {
// 取消之前的搜索
currentSearchOperation?.cancel()
// 创建新的搜索任务
let operation = BlockOperation {
// 检查取消
guard !Thread.current.isCancelled else {
print("搜索被取消: \(keyword)")
return
}
print("搜索: \(keyword)")
sleep(2) // 模拟网络请求
// 再次检查取消
guard !Thread.current.isCancelled else {
print("搜索被取消: \(keyword)")
return
}
let results = ["结果1", "结果2", "结果3"]
DispatchQueue.main.async {
completion(results)
}
}
currentSearchOperation = operation
searchQueue.addOperation(operation)
}
}
// 使用
let searchManager = SearchManager()
// 快速输入
searchManager.search(keyword: "a") { results in
print("结果: \(results)")
}
searchManager.search(keyword: "ab") { results in
print("结果: \(results)")
}
searchManager.search(keyword: "abc") { results in
print("结果: \(results)") // 只有这个会执行
}









网友评论