iT邦幫忙

2023 iThome 鐵人賽

DAY 22
0
Mobile Development

SwiftUI 男孩系列 第 22

Day 22: SwiftUI 有 Grand Central Dispatch ⌚️

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20231007/201301383e6oRhisiv.jpg
Photo by Sébastien Goldberg on Unsplash
Mount Cook, Nouvelle-Zélande

當你需要跟踪多個異步任務的完成時,DispatchGroup 是一個非常有用的工具。下面是一個使用 SwiftUI 和 DispatchGroup 的例子,其中我們模擬了從多個資源獲取數據的情境:

struct PublicSwimmingPoolsView: View {
    
    let pools = Bundle.main.decode([PoolsSection].self, from: "pools.json")
    @State private var data1: String = "Loading Data 1..."
    @State private var data2: String = "Loading Data 2..."
    @State private var allDataLoaded: Bool = false
    
    var body: some View {
        NavigationView {
            VStack {
                List {
									  /.../
                }
                Group {
                    VStack(spacing: 20) {
                        Text(data1)
                        Text(data2)
                        if allDataLoaded {
                            Text("All data loaded!")
                        }
                    }
                    .onAppear {
                        fetchData()
                    }
                }
            }
        }
        /.../
    }
    
    func fetchData() {
        let dispatchGroup = DispatchGroup()
        
        dispatchGroup.enter()
        DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
            self.data1 = "Data 1 Fetched!"
            dispatchGroup.leave()
        }
        
        dispatchGroup.enter()
        DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
            self.data2 = "Data 2 Fetched!"
            dispatchGroup.leave()
        }
        
        dispatchGroup.notify(queue: .main) {
            self.allDataLoaded = true
        }
    }
    
}

在這個例子中:

  1. 我們創建了一個 DispatchGroup
  2. 在啟動每個異步任務之前,我們調用 dispatchGroup.enter()
  3. 一旦異步任務完成,我們調用 dispatchGroup.leave()
  4. 使用 dispatchGroup.notify,我們可以設定一個塊,該塊將在所有的 .enter().leave() 匹配調用之後執行。在這裡,我們更新了 allDataLoaded 以在 UI 中表示所有數據都已加載。

這個模式對於確保多個異步任務都完成後再進行某些操作非常有用。

Tips : 每當開啟 dispatchGroup.enter(),確保 dispatchGroup.leave() ,要不然會永遠困在 dispatchGroup 🥺

我就遇到這 bug 單,特殊條件開啟新的 dispatchGroup.enter(),好多層 function 一層傳一層,最後沒加到 dispatchGroup.leave() 一行,突然找問題點藏很深 🥺


什麼!!妳還是不懂 dispatchGroup.enter() 沒有 dispatchGroup.leave(), dispatchGroup.notify 會怎樣?

來,開啟妳的啤酒,隨意坐坐 ~ 橋下說書人 Michael 來講故事:
https://ithelp.ithome.com.tw/upload/images/20231007/20130138aeHY2lQ1Qd.png

在古老的魔法大陸上,有個精靈法師公會,名叫「Dispatch Guild」。公會中有一座大樹,有樹門,稱為「Group Portal」。每當有一對新人要結婚,都要同一個時間分別獨自進入這魔法門參加試煉。他們會使用dispatchGroup.enter()這個咒語打開這座大門,分別進入另一個空間去完成任務。

https://ithelp.ithome.com.tw/upload/images/20231007/20130138RZc9alkATB.png

但是,這個空間有一個規則。每當一個法師使用dispatchGroup.enter()進入,門後的守護神就會增加一個計數。只有當每一位進入的法師都完成任務,使用dispatchGroup.leave()咒語後,計數才會減少。

為什麼這很重要呢?因為門後的守護神需要確保每位法師都安全返回。只有當所有的法師都回來,計數歸零時,dispatchGroup.notify的強大咒語就會被觸發,告訴大家:「冒險已經結束,可以回家了!」。

但是,傳說中有一些不小心的法師,他們進入空間後忘記使用dispatchGroup.leave()。守護神在無窮無盡的時間中等待著他們的返回。這使得另一半一起都被困在那個空間裡,無法返回現實世界,也無法啟動dispatchGroup.notify的強大咒語。

這是一個大問題!因為如果不小心,一對新人可能都會消失在那個空間中,永遠不會回來。

所以,每一次當一對新人進入那個空間,公會的長老都會嚴肅地警告他們:「當你完成你的任務,千萬不要忘記使用dispatchGroup.leave()這個咒語,否則你會使另一半陷入危機!」。

在數千年的時間裡,這些法師們學會了尊重這個咒語和守護神的規則。他們知道,只有這樣,他們才能保證每次冒險後都能安全返回,享受勝利的喜悅。

下集待續


上一篇
Day 21 : Figma 產生 SwiftUI code
下一篇
Day 23: Data binding: @State, @Binding, read-only property
系列文
SwiftUI 男孩30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言