Swift中不修改foo1(),如何让foo2()在foo1()之后执行?
问题解决:不修改foo1()让输出2在1之后
当前代码中,foo1()内部启动了一个异步Task,会在1秒后打印"1";而foo2()会被立即调用打印"2",默认输出顺序是2→1。由于要求不能修改foo1(),可以通过以下两种方式调整执行顺序:
1. 不可靠的固定等待(适合练习理解)
这种方式通过在调用foo2()前等待足够长的时间,确保foo1()内部的Task完成。优点是简单,缺点是不可靠——如果foo1()内部的Task执行时间变化,结果就会出错。
修改后的代码:
func foo1() { Task { try await Task.sleep(nanoseconds: 1_000_000_000) print("1") } } func foo2() { print("2") } func mainFunc() async { foo1() // 等待foo1的Task执行完成,额外预留100ms避免误差 try await Task.sleep(nanoseconds: 1_100_000_000) foo2() } // 启动异步的mainFunc Task { await mainFunc() }
2. 黑客式的Task追踪(仅用于学习探索,禁止生产环境使用)
由于foo1()没有暴露内部的Task引用,我们可以通过方法替换(Swizzling)来追踪所有创建的Task,然后等待foo1()启动的Task完成。这种方式会影响全局Task的行为,存在稳定性风险,仅适合学习Swift并发的底层机制。
修改后的代码:
import Foundation extension Task where Success == Void, Failure == Never { private static let originalInit = Task.init(priority:operation:) static var trackedTasks: [Task] = [] static func init(priority: TaskPriority? = nil, operation: @escaping @Sendable () async -> Void) -> Task { let task = originalInit(priority: priority, operation: operation) trackedTasks.append(task) return task } } func foo1() { Task { try await Task.sleep(nanoseconds: 1_000_000_000) print("1") } } func foo2() { print("2") } func mainFunc() async { let initialTaskCount = Task.trackedTasks.count foo1() // 等待foo1新启动的Task全部完成 let newTasks = Task.trackedTasks.dropFirst(initialTaskCount) for task in newTasks { await task.value } foo2() } // 启动异步的mainFunc Task { await mainFunc() }
核心结论
如果foo1()不主动暴露内部的异步任务(比如返回Task实例或提供completion handler),没有可靠且安全的方式从外部强制同步执行它的内部Task。上述两种方式仅适合练习场景,生产环境必须让foo1()提供异步任务的引用才能实现可靠等待。
内容的提问来源于stack exchange,提问作者Bruno De Vivo
相关产品推荐
相关产品推荐

