多執行緒:Operation和OperationQueue

生命週期

//都有共同特點,只讀屬性。 //是否準備 open var isReady: Bool { get } //是否執行 open var isExecuting: Bool { get } //是否取消 open var isCancelled: Bool { get } //是否完成 open var isFinished: Bool { get } //操作完成之後的回撥 open var completionBlock: (() -> Void)? 複製程式碼
-
let operation = Operation()
此時處於Pending狀態 - 依賴 新增完會進入Ready階段。此時操作物件會進入 準備就緒狀態 。
- 優先順序 設定之後會進入執行階段。queuePriority屬性決定了 進入準備就緒狀態下的操作 之間的開始執行順序。
- 完成之後會finished,並且有回撥。
- 完成之後的不能取消,取消可以在其他三個時刻。
依賴(dependency)
//新增依賴 open func addDependency(_ op: Operation) //移除依賴 open func removeDependency(_ op: Operation) 複製程式碼
//1.建立佇列 let queue = OperationQueue() //2.建立操作 let op1 = BlockOperation { print("操作1") } let op2 = BlockOperation { print("操作2") } //3.新增依賴 op2.addDependency(op1) //4.新增操作 queue.addOperation(op2) queue.addOperation(op1) 複製程式碼
列印結果:
操作1 操作2 複製程式碼
結論是:op2依賴於op1時,不管新增操作的順序如何,結果都是op1先執行,op2再執行。
- 新增依賴,改變操作順序。
在SDWebImage中
if (sself.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) { // Emulate LIFO execution order by systematically adding new operations as last operation's dependency [sself.lastAddedOperation addDependency:operation]; sself.lastAddedOperation = operation; } 複製程式碼
typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) { /** * Default value. All download operations will execute in queue style (first-in-first-out). 先進先出:這是佇列的資料結構 */ SDWebImageDownloaderFIFOExecutionOrder, /** * All download operations will execute in stack style (last-in-first-out). 後進先出:這是棧的資料結構 */ SDWebImageDownloaderLIFOExecutionOrder }; 複製程式碼
FIFO:先進先出:這是佇列的資料結構。
LIFO:這是棧的資料結構。
關於這兩個資料結構模型(暫且不講),因為後進的操作依賴於新進的操作,所以後進的操作要等先進的操作出隊之後在執行。
這就是根據依賴改變的佇列的執行順序。
- 不同佇列的操作可以依賴 。順序儲存不變。
- 不能相互依賴,會造成操作死鎖。
優先順序(queuePriority)
open var queuePriority: Operation.QueuePriority
預設normal
public enum QueuePriority : Int { case veryLow case low case normal case high case veryHigh } 複製程式碼
NSOperation 提供了queuePriority(優先順序)屬性,queuePriority屬性適用於同一操作佇列中的操作,不適用於不同操作佇列中的操作。
在SDWebImage中
if (options & SDWebImageDownloaderHighPriority) { operation.queuePriority = NSOperationQueuePriorityHigh; } else if (options & SDWebImageDownloaderLowPriority) { operation.queuePriority = NSOperationQueuePriorityLow; } 複製程式碼

取消操作
//取消操作 open func cancel() 複製程式碼
waitUntilFinished()
阻塞當前執行緒,直到該操作結束。可用於執行緒執行順序的同步。
print("begain") let opA = BlockOperation() opA.addExecutionBlock { print("操作A") } let opB = BlockOperation() opB.addExecutionBlock { print("操作B") } let queue = OperationQueue() queue.addOperations([opA,opB], waitUntilFinished: true) print("------") let opC = BlockOperation() opC.addExecutionBlock { print("操作C") } let opD = BlockOperation() opD.addExecutionBlock { print("操作D") } queue.addOperations([opC,opD], waitUntilFinished: true) print("end") 複製程式碼
列印結果
begain 操作A 操作B ------ 操作C 操作D end 複製程式碼
直到操作A、操作B完成之後,才能進行下面的操作
operation的實現類
因為operation是抽象類,所以使用的時候需要用子類或者繼承operation的子類。
BlockOperation
let opA = BlockOperation() opA.addExecutionBlock { print("操作A") } 複製程式碼
NSInvocationOperation
swfit中已經沒有這個類了,只在OC中。
繼承Operation
- 非併發:non-concurrent
main() 複製程式碼
必須重寫main()方法
class DownLoadOperation: Operation { override func main() { print("下載了") } } 複製程式碼
let opA = DownLoadOperation() let queue = OperationQueue() queue.addOperations([opA], waitUntilFinished: true) 複製程式碼
- 併發:concurrent
start() isAsynchronous isExecuting isFinished 複製程式碼
至少這幾個屬性和方法重寫
可以看SDWebimage封裝的opeation
operation流程化
可以看出opretaion可以繼承類,所以取代了程式碼塊,更加面向物件。
opretaion的生命週期可以看出,操作更加容易控制。
依賴是邏輯流程更加清晰可控。所以流程化複雜的場景更合適。
operationQueue

operation:操作,一個任務可以當做是一個操作。例如:下載任務,上傳任務,圖片編解碼任務,播放音視訊...都可以看做是一個操作。
operationQueue:操作佇列,這個操作佇列負責把放入佇列裡的操作,按照一定順序排程執行。