【iOS】#30 Dispatch Group 處理多個非同步操作

GCD, Dispatch Group

--

前陣子在面試時,遇到一個考題,有關於發 api 然後呈現抓到的圖片在 App 上。不過每次 api 的 response 只會有一個圖片網址,目標是按下一個按鈕後,呈現多張圖片在 App 中

在實作的過程中,就發現一些問題。先解析一下流程:抓 api ->圖片解析 -> -> 圖片裝入陣列 -> Reload Collection View。在這個過程中,需要等待前一個步驟有結果後,才能進行下一個動作,否則就沒有資料可以執行

所以一開始我解決的方式是使用 Closure,等待一個動作結束後執行下一個。然而很快就遇到下一個問題:

這個 api response 僅有一個圖片網址,我們需要的是多個圖片。如果按照我原本的做法,就會每抓到一個圖片就 Reload Collection View 一次,非常沒有效率

到最後我是多寫一個判斷,去看圖片抓了幾個,再一起 Reload Collection View,但程式碼不太簡潔也不太好讀

所以主考官給了一個建議,可以使用 Dispatch Group 改寫!

Dispatch Group

透過 Group 可以將多個 task 整合同步。當多個 task 附加到 Group 上時,可以安排這些 task 在同一個 queue 或者不同 queue 上進行非同步操作。當所有 task 都執行完畢時,Group 可以執行完成的操作

在 Dispatch Group 中有幾個 Function:

  • enter:宣告 task 進入 group
  • leave:宣告 task 在 group 已經執行結束
  • wait:等待前一個提交的 task 執行完畢
  • notify:當 group 中所有 task 皆執行完畢

範例

先建立抓取 Api 的 function 如下:

在一般執行的情況下,會像下圖,call function 從上到下,然而因為 fetchApi 需要一段時間運行,所以是先 print 出 executed,最後才是 api 抓到的結果

而加上 Dispatch Group 的結果如下,會等待所有 task 結束後,才 print 出 fetch done。在使用 group 時,要記得在 task 結束後使用 leave,否則會讓 group 以為 task 還在執行中

不過上面的方式不能確保哪個 Api 先被抓到,因為這是非同步的操作,只能知道最後會通知 group 然後做 completion。假設如果要等待第一個 fetchApi 結束再進行第二個的話,可以使用 wait()

wait 會讓當前 thread 暫時 block 住不繼續執行,等待目前在 group 中的 task 都執行結束後,再繼續下去。所以上面的程式碼在執行到第一個 fetchApi 時,會先等待他執行完,再執行以下程式碼,最後都執行結束後 notify 再進行 completion handler

這算是第一次接觸 GCD 的應用,過往只有概念以及使用 DispatchQueue.main.async。若有不清楚的地方還請大家見諒 XD,也歡迎大家提出來討論喔~

--

--