Operation基于GCD封裝, 完全面向?qū)ο? 對應(yīng)于GCD, Operation也有任務(wù)和隊列的概念, 只不過在Operation中任務(wù)(block)被稱為操作(operation).
Operation支持以下關(guān)鍵功能:
1.操作之間添加依賴
2.使用KVO監(jiān)聽操作的執(zhí)行狀態(tài)
3.對操作進行優(yōu)先級排序
4.取消操作
- 在GCD中, 任務(wù)代碼只能寫在block中, 并且需要放到隊列(dispatch queue)中去執(zhí)行.
- 在Operation中, 操作對象可以單獨執(zhí)行, 也可以添加到隊列 (operation queue)去執(zhí)行.
Operation是一個抽象類, 代表一個任務(wù). 通常我們使用它的子類NSInvocationOperation或NSBlockOperation來編寫任務(wù)代碼. 當(dāng)然也可以直接使用Operation, 不過需要重寫main方法, 在main里面編寫任務(wù)代碼.
1.創(chuàng)建方式
- NSInvocationOperation (swift不支持): 此類調(diào)用選擇器方法(selector), 在方法里面編寫任務(wù)代碼.
- BlockOperation : 此類采用block方式, 在block中編寫任務(wù)代碼.
- Operation: 需要繼承Operation建立子類违施,重寫main方法, 在main里面編寫任務(wù)代碼.
2.執(zhí)行方式
- 不添加到隊列, 手動調(diào)用operation的start方法.
- 添加到隊列, 系統(tǒng)自動調(diào)用start方法.
3.同步異步
Operation 沒有 GCD 中的sync 和 async 方法够颠。
蘋果文檔
如果計劃手動執(zhí)行操作對象膨处,而不是將其添加到隊列中,則可以將操作設(shè)計為以同步或異步方式執(zhí)行。默認情況下隶症,操作對象是同步的咙好。當(dāng)start()直接從代碼中調(diào)用同步操作的方法時渡蜻,該操作將在當(dāng)前線程中立即執(zhí)行辑莫。
默認情況下学歧,操作對象以同步方式執(zhí)行-也就是說,它們在調(diào)用其start方法的線程中執(zhí)行其任務(wù)各吨。
為了獲得最佳性能枝笨,您應(yīng)該將操作設(shè)計為盡可能異步,使應(yīng)用程序在執(zhí)行操作時可以自由地做其他工作揭蜒。
- 如果不使用OperationQueue, operation默認以同步方式執(zhí)行. 但我們有辦法使之異步執(zhí)行: 新建一個新線程, 然后在新線程里面調(diào)用start方法.
- 如果使用OperationQueue, 系統(tǒng)默認以異步方式執(zhí)行. 但我們可以使用waitUntilAllOperationsAreFinished 進行等待, 以確保操作完成后才繼續(xù)往下執(zhí)行.
4.隊列(OperationQueue)
隊列 (Operation Queue)有兩種: 主隊列和非主隊列 (自定義隊列).
- 主隊列通過OperationQueue.main獲得, 主隊列里的任務(wù)都是放到主線程執(zhí)行 (不包括使用addExecutionBlock:添加的額外操作, 因其可能在其他線程執(zhí)行).
- 非主隊列 (自定義隊列) 即一般 .init 出來的隊列, 默認在子線程中異步執(zhí)行. 通多設(shè)置最大并發(fā)數(shù)(maxConcurrentOperationCount)來控制隊列是串行還是并發(fā).
添加操作(任務(wù))到隊列有四種方式:
- addOperation: 添加一個現(xiàn)有的Operation (或者其子類).
- addOperations:waitUntilFinished: 可添加多個現(xiàn)有的Operation (或者其子類), 可設(shè)置等待所有操作完成后方可繼續(xù)往下執(zhí)行.
- addOperationWithBlock: 直接添加一個block
- addBarrierBlock: 添加?xùn)艡? 順帶一個任務(wù). 等柵欄前的所有任務(wù)都執(zhí)行完, 再執(zhí)行本柵欄的任務(wù), 起到隔離同步等待的目的.
5.串行并行
主隊列是串行隊列. 自定義隊列默認是并發(fā)隊列, 但可通多設(shè)置最大并發(fā)數(shù)(maxConcurrentOperationCount)來控制隊列是串行還是并發(fā).
maxConcurrentOperationCount
-1, 默認值, 并發(fā)隊列;
=0, 不執(zhí)行任何操作;
=1, 串行隊列;
<0, 除-1默認值外, 其他負值均報錯;
>1, 并發(fā)隊列, 如果數(shù)值過大, 最終并發(fā)數(shù)由系統(tǒng)決定.
6.基本用法
1.不使用 OperationQueue
// block operation
let blockOperation = BlockOperation {
for _ in 0...3 {
print("blockOperation:\(Thread.current)")
}
}
blockOperation.start()
//Operation
class CustomOperation: Operation {
override func main() {
print("\(#function), thread:\(Thread.current)")
}
}
在自定義Operation中, 調(diào)用start方法后, 系統(tǒng)會執(zhí)行多項安全檢查, 最終會調(diào)用main方法.
2.使用 OperationQueue
let operationQueue = OperationQueue() // 默認并發(fā)執(zhí)行
let blockOperation = BlockOperation {
for _ in 0...3 {
print("blockOperation:\(Thread.current)")
}
}
let blockOperationItem = BlockOperation {
for _ in 0...3 {
print("blockOperationItem:\(Thread.current)")
}
}
operationQueue.addOperation(blockOperation)
operationQueue.addOperation(blockOperationItem)
blockOperationItem:<NSThread: 0x600001d8e400>{number = 3, name = (null)}
blockOperation:<NSThread: 0x600001d98080>{number = 6, name = (null)}
blockOperation:<NSThread: 0x600001d98080>{number = 6, name = (null)}
blockOperationItem:<NSThread: 0x600001d8e400>{number = 3, name = (null)}
blockOperation:<NSThread: 0x600001d98080>{number = 6, name = (null)}
blockOperationItem:<NSThread: 0x600001d8e400>{number = 3, name = (null)}
blockOperation:<NSThread: 0x600001d98080>{number = 6, name = (null)}
blockOperationItem:<NSThread: 0x600001d8e400>{number = 3, name = (null)}
設(shè)置最大并發(fā)數(shù)
let operationQueue = OperationQueue() // 默認并發(fā)執(zhí)行
operationQueue.maxConcurrentOperationCount = 1
let blockOperation = BlockOperation {
for _ in 0...3 {
print("blockOperation:\(Thread.current)")
}
}
let blockOperationItem = BlockOperation {
for _ in 0...3 {
print("blockOperationItem:\(Thread.current)")
}
}
operationQueue.addOperation(blockOperation)
operationQueue.addOperation(blockOperationItem)
blockOperation:<NSThread: 0x6000021b4a00>{number = 3, name = (null)}
blockOperation:<NSThread: 0x6000021b4a00>{number = 3, name = (null)}
blockOperation:<NSThread: 0x6000021b4a00>{number = 3, name = (null)}
blockOperation:<NSThread: 0x6000021b4a00>{number = 3, name = (null)}
blockOperationItem:<NSThread: 0x6000021faac0>{number = 4, name = (null)}
blockOperationItem:<NSThread: 0x6000021faac0>{number = 4, name = (null)}
blockOperationItem:<NSThread: 0x6000021faac0>{number = 4, name = (null)}
blockOperationItem:<NSThread: 0x6000021faac0>{number = 4, name = (null)}
7.添加依賴
addDependency
let operationQueue = OperationQueue() // 默認并發(fā)執(zhí)行
operationQueue.maxConcurrentOperationCount = 1
let blockOperation = BlockOperation {
for _ in 0...3 {
print("blockOperation:\(Thread.current)")
}
}
let blockOperationItem = BlockOperation {
for _ in 0...3 {
print("blockOperationItem:\(Thread.current)")
}
}
let blockOperationItem2 = BlockOperation {
print("blockOperationItem2:\(Thread.current)")
}
blockOperationItem2.addDependency(blockOperationItem)
operationQueue.addOperation(blockOperation)
operationQueue.addOperation(blockOperationItem)
operationQueue.addOperation(blockOperationItem2)
8.設(shè)置優(yōu)先級
public enum QueuePriority : Int {
case veryLow = -8
case low = -4
case normal = 0
case high = 4
case veryHigh = 8
}
let operationQueue = OperationQueue() // 默認并發(fā)執(zhí)行
operationQueue.maxConcurrentOperationCount = 2
let blockOperation = BlockOperation {
for _ in 0...3 {
print("blockOperation:\(Thread.current)")
}
}
let blockOperationItem = BlockOperation {
for _ in 0...3 {
print("blockOperationItem:\(Thread.current)")
}
}
let blockOperationItem2 = BlockOperation {
print("blockOperationItem2:\(Thread.current)")
}
blockOperationItem2.addDependency(blockOperationItem)
blockOperationItem.queuePriority = .veryHigh
blockOperation.queuePriority = .low
operationQueue.addOperation(blockOperation)
operationQueue.addOperation(blockOperationItem)
operationQueue.addOperation(blockOperationItem2)
blockOperationItem:<NSThread: 0x6000032979c0>{number = 6, name = (null)}
blockOperation:<NSThread: 0x600003298100>{number = 4, name = (null)}
blockOperation:<NSThread: 0x600003298100>{number = 4, name = (null)}
blockOperation:<NSThread: 0x600003298100>{number = 4, name = (null)}
blockOperation:<NSThread: 0x600003298100>{number = 4, name = (null)}
blockOperationItem:<NSThread: 0x6000032979c0>{number = 6, name = (null)}
blockOperationItem:<NSThread: 0x6000032979c0>{number = 6, name = (null)}
blockOperationItem:<NSThread: 0x6000032979c0>{number = 6, name = (null)}
blockOperationItem2:<NSThread: 0x6000032979c0>{number = 6, name = (null)}
9. 通過addExecutionBlock方法添加block操作
let operationQueue = OperationQueue() // 默認并發(fā)執(zhí)行
operationQueue.maxConcurrentOperationCount = 2
let blockOperation = BlockOperation {
for _ in 0...3 {
print("blockOperation:\(Thread.current)")
}
}
let blockOperationItem = BlockOperation {
for _ in 0...3 {
print("blockOperationItem:\(Thread.current)")
}
}
blockOperationItem.addExecutionBlock {
for _ in 0...2 {
print("blockOperationItem addExecutionBlock:\(Thread.current)")
}
}
operationQueue.addOperation(blockOperation)
operationQueue.addOperation(blockOperationItem)
blockOperation:<NSThread: 0x6000028be9c0>{number = 7, name = (null)}
blockOperationItem:<NSThread: 0x6000028be700>{number = 5, name = (null)}
blockOperationItem addExecutionBlock:<NSThread: 0x6000028c4100>{number = 6, name = (null)}
blockOperationItem addExecutionBlock:<NSThread: 0x6000028c4100>{number = 6, name = (null)}
blockOperationItem addExecutionBlock:<NSThread: 0x6000028c4100>{number = 6, name = (null)}
blockOperationItem:<NSThread: 0x6000028be700>{number = 5, name = (null)}
blockOperation:<NSThread: 0x6000028be9c0>{number = 7, name = (null)}
blockOperationItem:<NSThread: 0x6000028be700>{number = 5, name = (null)}
blockOperation:<NSThread: 0x6000028be9c0>{number = 7, name = (null)}
blockOperationItem:<NSThread: 0x6000028be700>{number = 5, name = (null)}
blockOperation:<NSThread: 0x6000028be9c0>{number = 7, name = (null)}
可以看到横浑,通過addExecutionBlock 方法添加的代碼塊是在blockOperationItem開始執(zhí)行之后,另外開辟了一條新線程執(zhí)行的屉更。