UITabBarController切换子VC时异步API调用与取消时序问题如何处理
问题根因分析
- UITabBarController切换tab的系统生命周期有固定的执行顺序:新视图控制器的
viewWillAppear会先触发,旧视图控制器的viewWillDisappear后触发,这个系统逻辑无法直接修改。 - 你当前的
cancelAPI实现大概率是全局取消所有网络请求,没有区分请求所属的视图控制器,导致VC1执行取消操作时,把刚发起的VC2的请求也一并误删了。
解决方案
方案1:请求与所属VC绑定(最推荐)
每个VC单独管理自己发起的请求,取消时只处理当前VC自己的请求,完全规避跨VC误取消的问题,不受生命周期顺序影响。
实现示例:
在每个VC内维护专属的请求存储集合:
// 每个VC内部新增属性,用Moya的话就改为存储[Cancellable]类型 private var currentTasks: [Alamofire.Request] = [] func callAPI() { // 发起请求时将返回的请求实例存入当前VC的集合 let request = AF.request("你的接口地址").response { [weak self] res in // 请求完成后记得从集合中移除,避免内存泄漏 if let index = self?.currentTasks.firstIndex(where: { $0.task?.taskIdentifier == res.task?.taskIdentifier }) { self?.currentTasks.remove(at: index) } // 处理响应逻辑 } currentTasks.append(request) } func cancelAPI() { // 仅取消当前VC自己发起的请求 currentTasks.forEach { $0.cancel() } currentTasks.removeAll() }
方案2:调整取消逻辑执行时机
如果暂时不想改请求管理逻辑,可以将取消操作从viewWillDisappear移到viewDidDisappear,对于Tab切换场景,旧VC的viewDidDisappear触发时已经完全退出视图层级,此时即使是全局取消,也不会影响新VC已经发起的请求。但该方案只是临时规避,还是建议优先做请求隔离,避免其他场景出现类似问题。
方案3:通过TabBar代理调整执行时序
实现UITabBarController的代理方法,在切换tab前先执行旧VC的取消逻辑,从根源上修改执行顺序:
extension 你的自定义TabBarController: UITabBarControllerDelegate { func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool { // 拿到当前正在显示的旧VC,先执行取消逻辑 if let currentVC = selectedViewController as? 你的VC基类 { currentVC.cancelAPI() } return true } }
此时切换的执行顺序会变成:VC1 cancel API → VC2 call API,完全符合预期。
内容的提问来源于stack exchange,提问作者Beginnerrrrrr
相关产品推荐
相关产品推荐

