iOS-GCD-DispatchGroup, DispatchSemaphore介紹

Gordon Feng
程式愛好者
Published in
6 min readFeb 6, 2022
We all need a guy, who can tell you when to go, and where to go.

在開發iOS Application,我們常會遇到一個狀況是需要Task有特定的先後順序執行,最粗暴的方式就是不斷Call closure call back,但隨著牽涉的任務越多,closure包closure的層數也越來越多,導致程式碼越來越往右傾斜造成波動拳的既視感,既不好閱讀也不好維護。

Example of callback hell

上面所舉的就是一種很常見的例子,當我們需要所有API Response都回來後,再更新我們的畫面,像這樣的需求就很容易寫成所謂的Callback hell,目前有很多解法,像是我們今天要介紹到的DispatchGroupDispatchSemaphore、第三方套件Promise,還有最近Apple 推出的async/await寫法,都可以有效改善Callback hell的問題。

DispatchGroup

DispatchGroup 是一個可以監控所有你所指定任務的物件。
透過任務開始時執行group.enter跟任務結束後執行group.leave,DispatchGroup可以通知你哪些非同步的任務已經完成,你可以設計在所有任務完成後,再透過group.notify執行你所希望最後執行的任務。

舉個例子,我們常常會希望所有API完成後,再執行畫面更新,就可以透過DispatchGroup達成:

DispatchGroup example
fetchUserInfo(completion:) start
fetchWeatherInfo(completion:) start
loginAPI(completion:) start
fetchUserInfo(completion:) completed
fetchWeatherInfo(completion:) completed
loginAPI(completion:) completed
Reload user interface.

DispatchSemaphore

DispatchSemaphore可以決定一次執行多少非同步執緒,我們可以設定DispatchSemaphore.init(value: Int),告訴DispatchSemaphore每次執行多少非同步執行緒,透過在任務開始時執行DispatchSemaphore.wait(),告訴其他執行緒自已正在執行任務中,可使用資源-1(value -1)。
再透過完成任務後執行DispatchSemaphore.signal(),告訴其他執行緒任務已完成,釋出可使用資源(value +1)。
若value為負數,則該執行緒暫停,等待value大於、等於零後,才會繼續執行任務。

根據蘋果文件建議,我們有兩種方式可以使用DispatchSemaphore:
1. 將DispatchSemaphore value 設為0,我們可以將A任務指定在B任務結束後執行
2. 將DispatchSemaphore value 設為大於零,可以控制資源的使用

第一種方法的範例如下:

Start fetching user information.
Fetch user information completed.
Start reload UI.

範例需求是fetchUserInfo完成後,再執行reloadUI。
這有很多種方式可以達到,DispatchSemaphore就是其中一種,透過設定0給DispatchSemaphore,在執行fetchUserInfo後,我們呼叫.wait(),將value -1,使value為負數,執行緒暫停,等到fetchUserInfo完成後,呼叫.signal(),將value+1,value回到0,執行緒解除暫停,並繼續執行接下來的任務(reloadUI)。

第二種方法屬於資源控制。舉個例子來說,當我們需要下載15個檔案,但我們想三個檔案三個檔案下載,我們就可以使用DispatchSemaphore實現。

DispatchSemaphore example
Downloading 1 task
Downloading 2 task
Downloading 3 task
Download 1 task completed
Downloading 4 task
Download 4 task completed
Downloading 5 task
Download 3 task completed
Downloading 6 task
Download 2 task completed
Downloading 7 task
Download 5 task completed
Download 6 task completed
Downloading 8 task
Downloading 9 task
Download 8 task completed
Downloading 10 task
Download 9 task completed
Downloading 11 task
Download 7 task completed
Downloading 12 task
Download 11 task completed
Downloading 13 task
Download 10 task completed
Downloading 14 task
Download 14 task completed
Download 13 task completed
Downloading 15 task
Download 12 task completed
Download 15 task completed

上述例子我們可以觀察到,我們可以有效限制同時下載三個任務,每當有任務完成,DispatchSemaphore會馬上補一個等待中的任務開始執行,維持同時執行三個非同步下載程序,直到所有等待下載的任務都下載完成為止。

--

--