成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

實戰(zhàn)指南 | Swift 并發(fā)中的任務(wù)取消機制

開發(fā) 前端
這篇文章會講清楚任務(wù)取消的原理、如何正確使用它,以及如何寫出高效又優(yōu)雅的代碼。?

前言 

Swift 并發(fā)提供了一種協(xié)作式取消(cooperative cancellation) 機制,來讓任務(wù)在需要時自己退出。簡單來說,Swift 不會強行終止你的任務(wù),但它會告訴你任務(wù)已經(jīng)被標(biāo)記為取消,至于你要不要停下來,那是你自己的決定。

這篇文章會講清楚任務(wù)取消的原理、如何正確使用它,以及如何寫出高效又優(yōu)雅的代碼。

什么是協(xié)作式取消? 

協(xié)作式取消的核心思想是:

  • 調(diào)用方(比如 SwiftUI)沒法直接終止任務(wù),只能“標(biāo)記”為取消。
  • 任務(wù)本身需要定期檢查這個標(biāo)記,并決定要不要提前終止。
  • 你可以選擇直接返回、提供部分結(jié)果,或者繼續(xù)執(zhí)行,全看你的業(yè)務(wù)邏輯。

簡單來說,Swift 只是給你一個“信號”——“嘿,這個任務(wù)已經(jīng)沒用了,看看你要不要停下來”。

如何用 Task API 處理任務(wù)取消 

來看個例子,這是一個 SwiftUI 界面,用戶輸入搜索內(nèi)容時,會觸發(fā)異步搜索。

struct ContentView: View {
    @Stateprivatevar store = Store()
    @Stateprivatevar query = ""
    
    var body: some View {
        NavigationStack {
            List(store.results, id: \.self) { result in
                Text(verbatim: result)
            }
            .searchable(text: $query)
            .task(id: query) {
                await store.search(matching: query)
            }
        }
    }
}

這里最關(guān)鍵的是 task(id: query) 這行代碼:

  • 當(dāng) query 變化時,SwiftUI 會啟動一個新的搜索任務(wù)。
  • 同時,它會標(biāo)記上一個任務(wù)為“已取消”,但不會立刻終止它。
  • 如果舊任務(wù)里沒有檢查取消狀態(tài),它可能仍然會跑完所有邏輯。

這意味著,如果用戶輸入了很多字符,可能會同時存在多個搜索任務(wù),這就是為什么我們要手動處理取消邏輯。

在異步方法中正確處理取消 

假設(shè) Store 負責(zé)查詢數(shù)據(jù),我們的 search(matching:) 方法如下:

import HealthKit

@MainActor @Observablefinalclass Store {
    private(set) var results: [HKCorrelation] = []
    privatelet store = HKHealthStore()
    
    func search(matching query: String) async {
        let foodQuery = HKSampleQueryDescriptor(
            predicates: [.correlation(type: .init(.food))],
            sortDescriptors: []
        )
        
        do {
            let food = try await foodQuery.result(for: store)
            
            tryTask.checkCancellation()  // 檢查任務(wù)是否已取消
            
            results = food.filter { food in
                let title = food.metadata?["title"] as? String ?? ""
                return title.localizedStandardContains(query)
            }
        } catch {
            results = []
        }
    }
}

這里有個關(guān)鍵點:**Task.checkCancellation()**。

  • 這個方法會拋出一個錯誤,如果任務(wù)已經(jīng)被取消,它就會立刻停止執(zhí)行,后續(xù)的代碼不會再運行。
  • 這樣可以避免執(zhí)行一些不必要的邏輯,比如過濾數(shù)據(jù)、更新 UI 等。
  • 如果任務(wù)被取消,我們直接把 results 置空,這樣用戶不會看到過時的搜索結(jié)果。

在多個步驟中檢查取消狀態(tài) 

如果你的異步代碼有多個步驟,比如先獲取數(shù)據(jù)、然后再做一些處理,那你可能需要在多個關(guān)鍵點檢查任務(wù)是否已取消,否則即使任務(wù)已經(jīng)無效了,它可能還會跑完整個流程。

import HealthKit

@MainActor @Observablefinalclass Store {
    private(set) var results: [HKCorrelation] = []
    privatelet store = HKHealthStore()
    
    func search(matching query: String) async {
        let foodQuery = HKSampleQueryDescriptor(
            predicates: [.correlation(type: .init(.food))],
            sortDescriptors: []
        )
        
        do {
            let food = try await foodQuery.result(for: store)
            
            tryTask.checkCancellation()  // 第一次取消檢查
            
            // 假設(shè)這里有額外的數(shù)據(jù)處理
            tryTask.checkCancellation()  // 第二次取消檢查
            
            results = food.filter { food in
                let title = food.metadata?["title"] as? String ?? ""
                return title.localizedStandardContains(query)
            }
        } catch {
            results = []
        }
    }
}

為什么要多次檢查?

  • 如果 foodQuery 運行了一段時間,任務(wù)被取消了,我們希望盡早停下來,而不是等所有代碼都跑完。
  • 某些任務(wù)可能是分步執(zhí)行的,比如先獲取原始數(shù)據(jù),再處理數(shù)據(jù)。如果第一步完成了,但任務(wù)已經(jīng)取消了,我們就沒必要繼續(xù)處理數(shù)據(jù)。

用 isCancelled 進行檢查 

除了 Task.checkCancellation() 之外,Swift 還提供了 Task.isCancelled 這個屬性,它是一個布爾值,你可以用它更靈活地處理任務(wù)取消:

actor SearchService {
    privatevar cachedResults: [HKCorrelation] = []
    privatelet store = HKHealthStore()
    
    func search(matching query: String) async throws -> [HKCorrelation] {
        guard !Task.isCancelled else {
            return cachedResults  // 任務(wù)取消了,直接返回緩存
        }
        
        let foodQuery = HKSampleQueryDescriptor(
            predicates: [.correlation(type: .init(.food))],
            sortDescriptors: []
        )
        
        let food = try await foodQuery.result(for: store)
        
        guard !Task.isCancelled else {
            return cachedResults  // 任務(wù)取消了,避免不必要的計算
        }
        
        cachedResults = food.filter { food in
            let title = food.metadata?["title"] as? String ?? ""
            return title.localizedStandardContains(query)
        }
        
        return cachedResults
    }
}

兩種方式的區(qū)別:

  • Task.checkCancellation():如果任務(wù)已取消,直接拋出錯誤,代碼不再繼續(xù)執(zhí)行。
  • Task.isCancelled:任務(wù)是否繼續(xù)執(zhí)行,由你自己決定,比如可以提前返回緩存數(shù)據(jù),而不是直接終止

手動取消任務(wù) 

通常情況下,Swift 會幫你管理任務(wù)的取消,但如果你想手動創(chuàng)建和取消任務(wù),也可以用 Task:

struct ExampleView: View {
    @Stateprivatevar store = Store()
    @Stateprivatevar task: Task<Void, Never>?
    
    var body: some View {
        VStack {
            Button("開始任務(wù)") {
                task = Task {
                    await store.fetch()
                }
            }
            
            Button("取消任務(wù)") {
                task?.cancel()
            }
        }
    }
}

這里 task?.cancel() 只會標(biāo)記任務(wù)為取消,但不會真的終止它,所以你仍然需要在 fetch() 里檢查 Task.isCancelled 或 Task.checkCancellation()。

總結(jié) 

  • Swift 不會自動終止任務(wù),只會標(biāo)記它為取消。
  • 用 Task.checkCancellation() 可以立即終止任務(wù),防止執(zhí)行不必要的邏輯。
  • 用 Task.isCancelled 可以更靈活地決定如何處理取消。
  • 如果任務(wù)有多個異步步驟,應(yīng)該在關(guān)鍵點多次檢查取消狀態(tài)。
  • 手動創(chuàng)建的任務(wù)可以用 .cancel() 取消,但仍然需要手動檢查取消狀態(tài)。

學(xué)會這些,你的 Swift 并發(fā)代碼就能更高效、更優(yōu)雅地處理任務(wù)取消,讓用戶體驗更流暢!

責(zé)任編輯:姜華 來源: Swift社區(qū)
相關(guān)推薦

2014-07-29 11:20:28

Swift豆瓣電臺編程實戰(zhàn)

2022-04-26 08:41:38

Swift并發(fā)系統(tǒng)iOS

2025-03-19 09:02:18

Debouncing任務(wù)讓步Swift

2025-04-07 01:02:00

GoAPI語言

2024-04-09 08:04:42

C#結(jié)構(gòu)await

2023-04-26 11:59:06

Swift異步編程

2024-05-11 08:31:20

中斷機制插隊機制React

2021-02-02 14:55:48

React前端高優(yōu)先

2018-03-15 16:45:47

前端JavaScriptthis

2011-12-12 11:16:02

iOS并發(fā)編程

2023-11-06 14:13:51

asyncio開發(fā)

2024-08-09 10:59:01

KubernetesSidecar模式

2025-03-26 00:55:00

2020-11-20 07:51:02

JavaSPI機制

2017-01-13 22:42:15

iosswift

2021-07-22 09:43:09

Golang語言并發(fā)機制

2009-06-02 10:32:30

Oracle并發(fā)處理

2013-12-12 16:44:25

Lua協(xié)程

2021-10-15 09:56:10

JavaScript異步編程
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 亚洲综合天堂网 | 日韩欧美中文 | 99精品欧美一区二区三区综合在线 | 欧美日韩综合精品 | 中文字幕久久精品 | 国产欧美一级二级三级在线视频 | 亚洲人在线 | 婷婷激情综合 | 老外黄色一级片 | 欧美精品乱码99久久影院 | 久久成人av | 日日碰狠狠躁久久躁婷婷 | 亚洲精品久久久久久久久久吃药 | 日韩欧美视频 | 色吊丝2288sds中文字幕 | 欧美狠狠操 | 久久最新精品 | 色视频网站免费 | 日韩精品免费在线观看 | yiren22 亚洲综合 | 成人亚洲综合 | 激情一区二区三区 | 亚洲欧美一区二区三区情侣bbw | 91精品国产综合久久久久久丝袜 | av电影一区 | 天天拍天天操 | 久久久视频在线 | 成人三级av | 国产一区二区三区在线 | 97视频在线免费 | 在线精品一区 | 一级片在线免费看 | 操久久| 91九色视频在线 | 国产网站在线免费观看 | 久久成人精品 | 国产99免费视频 | av男人的天堂av| 日韩精品免费 | 亚洲www | 欧美黄色性生活视频 |