1. 程式人生 > >SDWebimage相關知識點1-- NSOperation

SDWebimage相關知識點1-- NSOperation

先進先出 特定 nsthread 來講 才會 enc prior 工作區 計算機

GCD GCD是最常用的管理並行代碼和執行異步操作的Unix系統層的API。GCD構造和管理隊列中的任務。 隊列是按先進先出(FIFO)管理對象的數據結構。隊列類似電影院的售票窗口,票的銷售是誰先到誰先服務。在等待線前面的人先去買他們的門票,在其余的後抵達的人之前。隊列在計算機科學中是相似的,因為第一個添加到隊列的對象也是第一個從隊列中刪除的對象。 操作隊列 NSOperationQueue GCD是一個底層的C的API,它使開發人員能夠並行地執行任務。操作隊列,另一方面,是高度抽象的隊列模型,是建立在GCD之上的。這意味著你可以並行執行任務就像GCD一樣,但以面向對象的方式。簡而言之,隊列操作讓編程更加簡單。 不同於GCD,它們不按先進先出的順序。下面是操作隊列和調度隊列的不同點: 1.不遵循先進先出:在操作隊列中,你可以設置一個操作的執行優先級,你可以添加操作之間的依賴關系,這意味著你可以定義一些操作完成後才會執行其他操作。這就是為什麽它們不遵循先進先出。 2.默認情況下,它們同時操作:然而你不能把它的類型改變成串行隊列。通過使用操作之間的依賴關系,在操作隊列還存在一個工作區來依次執行任務。 3.操作隊列是類NSOperationQueue的實例,其任務封裝在NSOperation的實例裏。 NSOperation 是蘋果提供的一套多線程解決方案,實際上NSOperation是基於GCD 更高一層的封裝,但是比GCD 更簡單易用、代碼可讀性更高。 需要配合NSOperationQueue 來實現多線程。 默認情況下,單獨使用NSOperation時系統執行同步操作,並沒有開辟新線程的能力,只有和配合NSOperationQueue 才能實現異步執行。 因為NSOperation是基於GCD的,那麽使用起來也和GCD差不多,其中,NSOperation相當於GCD中的任務,而NSOperationQueue則相當於GCD中的隊列。NSOperation實現多線程的使用步驟分為三步:
  1. 創建任務:先將需要執行的操作封裝到一個NSOperation對象中。
  2. 創建隊列:創建NSOperationQueue對象。
  3. 將任務加入到隊列中:然後將NSOperation對象添加到NSOperationQueue中。
之後呢,系統就會自動將NSOperationQueue中的NSOperation取出來,在新線程中執行操作。 NSOperation是一個抽象類,它不能直接使用,所以你必須使用NSOperation子類。在iOS SDK裏,我們提供兩個NSOperation的具體子類。這些類可以直接使用,但你也可以繼承NSOperation來創建自己的類來執行操作。我們可以直接使用的兩個類: 1.NSBlockOperation——使用這個類來用一個或多個block初始化操作。操作本身可以包含多個塊。當所有block被執行操作將被視為完成。
2.NSInvocationOperation——使用這個類來初始化一個操作,它包括指定對象的調用selector。 或者定義繼承自NSOperation的子類,通過實現內部相應的方法來封裝任務。 NSOperationQueue 和GCD中的並發隊列、串行隊列不同的是,NSOperationQueue 一共有兩種隊列:主隊列、其他隊列。 其他隊列中包含了串行、並發功能。 NSOperationQueue *queue = [NSOperationQueue mainQueue];//主隊列 NSOperationQueue *queue = [[NSOperationQueue alloc] init];//其他隊列
將任務加入到隊列中 1.先創建任務,再將創建好的任務加入到創建好的隊列中去 - (void)addOperation:(NSOperation *)op; 2.無需創建任務,在block中執行任務,直接將任務block加入到隊列中 (void)addOperationWithBlock:(void (^)(void))block; 控制串行執行和並發執行的關鍵 最大並發數:maxConcurrentOperationCount 默認情況下是-1,表示不進行限制,默認為並發執行。 當為1時,進行串行執行。 當>1時,進行並發執行。 操作依賴 NSOperation和NSOperationQueue最吸引人的地方是它能添加操作之間的依賴關系。比如說有A、B兩個操作,其中A執行完操作,B才能執行操作,那麽就需要讓B依賴於A。 - (void)addDependency 一些其他的方法:
  • - (void)cancel; NSOperation提供的方法,可取消單個操作
  • - (void)cancelAllOperations; NSOperationQueue提供的方法,可以取消隊列的所有操作
  • - (void)setSuspended:(BOOL)b; 可設置任務的暫停和恢復,YES代表暫停隊列,NO代表恢復隊列
  • - (BOOL)isSuspended; 判斷暫停狀態
註意: 這裏的暫停和取消並不代表可以將當前的操作立即取消,而是當當前的操作執行完畢之後不再執行新的操作
  • 暫停和取消的區別就在於:暫停操作之後還可以恢復操作,繼續向下執行;而取消操作之後,所有的操作就清空了,無法再接著執行剩下的操作。
自定義子類: 使用main方法,不需要管理一些狀態屬性(如isExecuting 和 isFinished ),當main 方法返回的時候,這個operation 就結束了。 這種方式使用起來非常簡單,main方法執行完就認為operation 結束了。所以一般可以用來執行同步任務。 如果你希望擁有更多的控制權,或者想在一個操作中可以執行異步任務,那麽就重寫start 方法。 在這種情況下,必須手動管理操作的狀態,只有當發送isFinished 的kvo 消息時,才認為是operation 結束。 技術分享圖片
所以NSOperation的優勢是什麽? 1.首先,它們通過NSOperation類裏的方法addDependency(op:NSOperation)支持依賴。當你需要開始一個依賴於其它操作執行的操作,你會需要NSOperation。 2.其次,你可以通過下面這些值設置屬性queuePriority來改變執行優先級: 3.對於任何給定的隊列,你可以取消一個特定的或所有的操作。操作可以在被添加到隊列後被取消。取消是通過調用NSOperation類裏的方法cancel()。當你取消任何操作的時候,我們有三個場景,其中一個會發生: 你的操作已經完成。在這種情況下,取消方法沒有效果。 你的操作已經被執行。在這種情況下,系統不會強制操作代碼停止,而是屬性cancelled被置為true。 你的操作仍在隊列中等待。在這種情況下,你的操作將不會被執行。 4.NSOperation有3個有用的布爾屬性,finished、 cancelled和ready。一旦操作執行完成,finisher將被置為true。一旦操作被取消,cancelled將被置為true。一旦準備即將被執行,ready將被置為true。 5.任何NSOperation有一個選項來設置回調,一旦任務完成將會被調用。在NSOperation裏,一旦屬性finished被置為true,這個block將被調用。 原理探析: demo: - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. [self configurationQueue]; LDNSOperation *operation = [[LDNSOperation alloc] init]; [self.operationQueue addOperation:operation]; [NSThread sleepForTimeInterval:3]; [operation cancel]; } -(void)configurationQueue{ self.operationQueue = [[NSOperationQueue alloc] init]; self.operationQueue.maxConcurrentOperationCount = 4; } LDNSOperation為NSOperation的子類,重寫start方法: -(void)start{ while (true) { if(self.cancelled){ NSLog(@"已經取消"); return; } NSLog(@"start"); [NSThread sleepForTimeInterval:1]; } } 1. [self.operationQueue addOperation:operation]; 添加一個未完成的NSOperation ,其實就是將NSOperation 添加到一個動態的數組中。 技術分享圖片 internal 就是一個內部類,指的是NSOperationQueue 。 使用了KVO手動通知,進行operations 和 operationCount 的改變通知。 技術分享圖片 完成的話,就從operations 中刪除。 如果準備完成,就添加到waiting 中,等待被執行。 _execute 方法: 技術分享圖片 如果沒有暫停,就從waiting 中取出第一個,並且刪除waiting 中的這個數據。 添加isFinished 屬性觀察 如果是並發的話,就馬上執行。 如果不是,使用detachNewThreadSelector來創建新的線程去執行start。 所有的線程都很忙,並且沒有達到threadCount最大值時,會創建新的線程。 _execute 是一個執行隊列,依次將等待隊列裏所有的operation 進行start 。 對於start 函數來講,一個NSOperation 並沒有新建一個線程。 依然操作在[NSTread currentThread]中。 現在來思考下,也就明白了為什麽NSOperationQueue要有兩種處理方式了,如果NSOperation支持並發,然後NSOperationQueue在為其分配線程,那就是線程裏面又跑了一條線程,這樣就很尷尬了,通過isConcurrent可以避免這種現象。

SDWebimage相關知識點1-- NSOperation