You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中如何等待async/await函数执行完成后再执行后续代码?

Swift中async函数未等待执行完成的解决方法

你遇到的问题是:调用await res.checkExistingUser(email: loginForm.email)后,后续的print("after that")没有等待该函数执行完毕就运行了。这是因为你的checkExistingUser方法虽然标记为async,但内部使用的是闭包回调式的API调用,函数本身会在发起API请求后立即返回,并没有真正挂起协程等待回调完成,导致await无法起到等待作用。

解决思路

把基于闭包的异步API包装成支持async/await的形式,利用Swift的withCheckedThrowingContinuation(或withCheckedContinuation,无错误场景)将回调结果传递给协程,让函数真正等待API请求完成后再返回。

修改后的代码实现

1. 改造ViewModel中的checkExistingUser方法

将原来的闭包回调逻辑替换为async/await调用:

@MainActor
final class LoginViewModelImpl: LoginViewModel {
    @Published var hasError = false
    @Published private(set) var errorMesg = ""
    @Published private(set) var isFetching = false
    @Published private(set) var isLoggedIn = false
    @Published private(set) var isVerify = false
    
    func checkExistingUser(email: String) async {
        self.isFetching = true
        let res = UserServiceImpl()
        
        do {
            // 调用包装后的async版本API
            let apiListingResponse = try await res.checkExistingUserAsync(email: email)
            print(apiListingResponse)

            if !apiListingResponse.success {
                self.hasError = true
                self.errorMesg = String(localized: String.LocalizationValue(apiListingResponse.error?.message ?? ""))
                self.isFetching = false
                return
            }
            
            if apiListingResponse.payload?.message != nil {
                self.isVerify = false
                self.hasError = true
                self.errorMesg = String(localized: String.LocalizationValue("verify_email"))
                self.isFetching = false
                return
            }
            
            // 这里添加其他成功场景的逻辑
            self.isFetching = false
        } catch {
            // 统一处理API请求错误
            self.hasError = true
            self.errorMesg = error.localizedDescription
            self.isFetching = false
        }
    }
}

2. 给UserServiceImpl添加async版本的API方法

通过withCheckedThrowingContinuation包装原有的闭包式API:

extension UserServiceImpl {
    func checkExistingUserAsync(email: String) async throws -> BasedResponse<UserExistModel> {
        return try await withCheckedThrowingContinuation { continuation in
            self.checkExistingUser(email: email)
                .responseDecodable(of: BasedResponse<UserExistModel>.self) { response in
                    switch response.result {
                    case .success(let model):
                        // 成功时返回结果,恢复协程
                        continuation.resume(returning: model)
                    case .failure(let error):
                        // 失败时抛出错误,恢复协程
                        continuation.resume(throwing: error)
                    }
                }
        }
    }
}

原理说明

  • withCheckedThrowingContinuation会创建一个“续体”(continuation),暂停当前协程,直到我们手动调用resume方法。
  • 当API的闭包回调返回结果时,调用continuation.resume传递成功结果或错误,协程会恢复执行,此时checkExistingUser方法才会真正返回,外部的await才能正确等待整个流程完成。

这样修改后,你原来的调用代码:

await res.checkExistingUser(email: loginForm.email)
print("after that") // 现在会等待上面的函数执行完成后再运行

就能正常按顺序执行了。

内容的提问来源于stack exchange,提问作者Mixko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 05:25:46