DispatchGroup操作

走在cs的療癒之路上
6 min readMay 6, 2018

--

以DispatchQueue為基礎,來使用DispatchGroup。

會使用到DispatchGroup, 好處是可以用較好的閱讀性,很容易就達到彈性的多工作業設定,例如:

(1)group裡的 dispatchQueue 的任務都完成後, 才需要更新UI 。
(2)可以選擇要不要等待某一個DispatchQueue,或是同一時間執行。(3)設定dispatchQueue的 優先順序

舉個例,用到的場景是:

當遇到call api結束後,要再接著 call 另一隻 api,

程式就會變成,越來越往斜的發展:

雖然Code是沒問題,但要花多點時間閱讀理解這段Code,

尤其是遇到還不止2個call api 任務,如果是3個,4個,5個…

加上跟 UI 上的互動。

程式寫完了,但是一點都不想去Debug裡面。

例如:

好在iOS有提供不同的方式,可以解決這個問題,而且變得更好閱讀。就是使用DispatchQueue的方式來達成。

將以三種不同範例,來說明如何改寫:

  1. 使用Completion方式(要改進的目標)
  2. 使用DispatchGroup
  3. 使用DispatchSemaphore

1. 使用Completion方式(要改進的目標)

假設有4件事,且希望有順序性:
①取得Server timestamp ->
②送出變更資料請求,需帶timestamp ->
③ 變更成功後,寫入資料 ->
④ 當資料變更時,UI更新

為了方便觀看跑的順序,print出每個步驟:

列印出結果,如我們所期望的:

2. 使用DispatchGroup (async情況)

a. Step1: dispatchQueue + dispatchGroup + notify = response 不照順序完成

程式變得比較容易理解,有3個任務,都對應到group,當group裡的任務都完成後,執行更新ui的動作

但…..結果不是如我期望的那樣。 而且回來的結果還不是依照順序

再跑一次的結果,也是一樣

b. Step2: dispatchQueue + dispatchGroup + notify + 「 enter , leave」= 一樣, response 沒有按照順序

enter leave,是需要搭配一對的語法,總該可以吧

執行結果,似乎開始的順序對了,但是任務2應該要等任務1回傳後才開始執行

在執行一次,結果:

沒有任何效果,只有觀察出顯示UI終於是在最後一步,但是網路更新行為仍然錯誤(我們期望是任務1完成,接著任務2, 任務2完成,接著任務3,),這不是我們要的。

c. dispatchQueue + dispatchGroup + notify + enter , leave +『wait 』= 依序等待前一個dispatchQueue結束, 才開始下一個, 👍

再次改寫,使用wait(),須注意使用,它會block該Queue,要注意有可能造成deadlock。

結果

終於是我們要的了👍

3. 使用DispatchSemaphore

結果如期望,

這與DispatchGroup的 enter 與 leave 與 wait 方法有點像,但是又不一樣,因為透過DispatchSemaphore(value: 0) 可以決定同一時間跑任務的數量

如果設定DispatchSemaphore(value: 1),結果會是

也就是同一時間任務1,2是concurrent,如果是要有順序的話是不能這樣用。

另外說如果不care任務1~3的順序,但是任務4更新ui需要等任務1~3完成。那我們仍然需要使用enter,leave。

DispatchQueue與Operation比較

相同的是

・同樣都是在並行設計會用到。
・一樣可以設定優先等級

不同的是

・Operation並不遵循FIFO方式,而DispatchQueue則是會。
・Operation可以使用cancel, DispatchQueue沒有。

特別的是

・Operation可以透過增加任務間的依賴性,來達到序列執行。
・DispatchQueue方式,可以快速把一段代碼塞進去任務後,並且說明任務執行方式是要同步執行還是異步執行。
・DispathGroup可以讓多個任務DispatchQueue,一旦完成後,就來執行notify裡的程式碼,這邊拿來放UI更新,也就是說經過一連串的網路下載資料、解析資料,都完成後,才來更新UI。

--

--