DispatchGroup操作
--
以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的方式來達成。
將以三種不同範例,來說明如何改寫:
- 使用Completion方式(要改進的目標)
- 使用DispatchGroup
- 使用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。