Swift中函数内Task异步任务未在函数结束前执行完成问题
Task {} 初始化时会将闭包内的异步逻辑提交到系统协作线程池排队调度,不会阻塞当前同步执行流:创建Task的语句执行完后,外层代码会立刻继续向下运行,等当前同步代码执行完毕、执行权交回给并发调度器时,Task闭包里的代码才会被调度执行,这就是你看到打印顺序为1,8,2,3,4,6,7的核心原因。
同步函数本身不具备等待异步任务执行完成的能力——Swift并发模型规定,只有被async标记的异步上下文,才能通过await关键字挂起、等待异步操作执行完毕。你当前写的checkForLoggedInUser是同步函数,自然不可能在函数返回前等待内部创建的独立Task跑完。
根据你的调用场景二选一即可:
方案1:将方法改为async函数,移除多余的Task包装,直接await内部异步逻辑
如果调用方本身处于异步上下文中,直接给方法加上async标记,去掉独立的Task创建逻辑,所有异步操作直接用await挂起等待,方法会在所有内部逻辑执行完成后才返回:func checkForLoggedInUser() async { self.isAuthenticating = true if await dataManager.isUserLogged() { do { self.loggedInUser = try await dataManager.fetchMe() } catch { self.error = error } } self.isAuthenticating = false }调用时在异步上下文里通过
await checkForLoggedInUser()触发即可。方案2:必须从同步上下文触发逻辑时,放弃「方法返回前任务执行完」的预期,通过状态响应结果
如果调用场景是同步的(比如UIKit的viewDidLoad、SwiftUI的onAppear默认同步逻辑中触发),不要强行让同步方法等待异步任务,否则会阻塞当前线程(大概率是主线程)导致UI卡死甚至死锁。你代码中已经定义了isAuthenticating、loggedInUser、error三个状态属性,直接通过属性观察、@Published订阅、KVO等方式监听状态变化,在isAuthenticating被置为false(即任务执行完毕)时再触发后续UI刷新或业务逻辑即可。
禁止为了等待Task完成在同步方法中使用信号量、轮询锁等阻塞当前线程的写法,这类写法会直接破坏Swift并发的调度逻辑,稳定性极差。
内容的提问来源于stack exchange,提问作者TheKingArthas

