在前幾天的文章裡,我們已經初步認識了 Swift 的非同步處理方式,包含 async/await 的基本使用方法以及與 其運用的實例。非同步程式碼與執行緒 (Threads) 之間的關係。
非同步處理並不代表程式碼一定會開新執行緒
,async/await
的重點是將非同步流程用同步的寫法表達,提升程式的可讀性。但實際上,任務仍然需要在某些執行緒上運行:
主執行緒 (Main Thread):負責 UI 更新,任何跟介面有關的操作都必須在這裡進行。
背景執行緒 (Background Threads):適合處理耗時任務,例如網路請求、檔案存取或影像處理。
如果把 UI 更新放到背景執行緒,常見的結果就是畫面不會更新或是發生錯誤。
以下範例說明 async/await 之下,任務可能切換執行緒:
func fetchData() async {
print("Step 1: \(Thread.isMainThread)") // 預設在主執行緒
let data = await loadNetworkData()
print("Step 2: \(Thread.isMainThread)") // 很可能在背景執行緒
await MainActor.run {
print("Step 3: \(Thread.isMainThread)") // 因為MainActor的設定回到主執行緒
updateUI(with: data)
}
}
func loadNetworkData() async -> String {
try? await Task.sleep(nanoseconds: 1_000_000_000) // 模擬耗時作業
return "Server Data"
}
func updateUI(with text: String) {
// 更新 UI 元件
}
MainActor 是 Swift Concurrency 裡專門處理 UI 的解決方案。我們可以將一個方法或屬性標註為 @MainActor,確保它一定在主執行緒上執行:
@MainActor
func updateUI(with text: String) {
label.text = text
}
//或是:
await MainActor.run {
}