如何在UIKit应用中关闭初始ViewController并终止后台动画?
解决ViewController跳转后后台运行、Lottie动画未停止的问题
问题根源
- 你的代码逻辑存在错误:在
dismiss的回调中使用self.present新控制器,此时self仍指向原ViewController实例,该实例会因为持有新控制器而无法被系统释放,导致后台动画持续运行。 - 若ViewController是应用的初始根控制器,调用
self.dismiss完全无效——这个方法仅用于关闭被present出来的控制器,根控制器本身不存在"被present"的状态。
方案一:替换根控制器(推荐)
如果无需再返回原ViewController,直接将XYZViewController设置为新根控制器,原ViewController会被系统自动释放,动画也会彻底停止。
修改presentNextViewController方法如下:
@objc func presentNextViewController() { // 先主动停止Lottie动画,减少资源消耗 onboardingLottieView.stop() let storyboard = UIStoryboard(name: "Main", bundle: nil) guard let vc = storyboard.instantiateViewController(withIdentifier: "XYZViewController") as? XYZViewController else { return } // 获取当前应用窗口并替换根控制器 if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, let window = windowScene.windows.first { window.rootViewController = vc window.makeKeyAndVisible() } }
方案二:基于导航控制器的正确跳转
如果初始ViewController是导航控制器的根节点,可通过push跳转后移除原控制器,确保其被释放:
前提:你的初始控制器必须是
UINavigationController,且根ViewController为当前的ViewController。
修改presentNextViewController方法:
@objc func presentNextViewController() { onboardingLottieView.stop() let storyboard = UIStoryboard(name: "Main", bundle: nil) guard let vc = storyboard.instantiateViewController(withIdentifier: "XYZViewController") as? XYZViewController else { return } // 跳转到新控制器 navigationController?.pushViewController(vc, animated: true) // 从导航栈中移除原ViewController,确保它被系统释放 if let index = navigationController?.viewControllers.firstIndex(of: self) { navigationController?.viewControllers.remove(at: index) } }
额外优化建议
- 避免使用
Timer.scheduledTimer的selector写法,改用闭包形式并添加弱引用,防止循环引用导致内存泄漏:
Timer.scheduledTimer(withTimeInterval: 3, repeats: false) { [weak self] _ in self?.presentNextViewController() }
内容的提问来源于stack exchange,提问作者perps4214213
相关产品推荐
相关产品推荐

