Swift Storyboard视图管理疑问:视图是否真关闭?同页pop+push是否合规?
iOS视图跳转内存与导航栈操作问题解答
一、模态跳转的内存疑问
你通过present切换视图的代码:
let viewController = self.storyboard!.instantiateViewController(withIdentifier: "HomeViewController") viewController.modalPresentationStyle = .fullScreen self.present(viewController,animated: true, completion:nil)
这种方式并没有关闭或销毁原视图控制器,原控制器只是被新的模态控制器覆盖,其实例仍会保存在内存中。原因是模态呈现的机制里,发起present的控制器会持有新弹出的控制器,同时自身会被系统保留(作为模态控制器的presentingViewController),只有当你调用dismiss方法关闭模态控制器后,原控制器才有可能被系统回收(前提是没有其他强引用)。如果频繁用这种方式跳转且不主动清理,确实会造成多控制器实例留存,浪费内存资源。
二、导航控制器连续pop和push的正确性
你在View1跳转到View2时连续执行pop和push的写法不正确,问题点如下:
- 如果View1是导航栈的根控制器,调用
popViewController(animated: true)不会产生任何效果(返回nil),此时直接push View2会让栈结构变成[View1, View2],完全达不到你“避免多视图留存”的目的。 - 即使当前控制器不是根,
pop是带动画的异步操作,立刻执行push会干扰导航栈的状态,可能导致动画混乱、栈结构异常,甚至引发崩溃。
针对你的需求的正确写法
如果需要从View1跳转到View2时,彻底移除View1让View2成为新根(避免留存),应该直接替换导航栈的根控制器:
let storyboard = UIStoryboard(name: "Main", bundle: nil) let viewController = storyboard.instantiateViewController(identifier: "View2") self.navigationController?.setViewControllers([viewController], animated: true)
如果只是正常跳转(保留View1在栈中,方便后续返回),直接执行push即可,不需要额外的pop操作:
let storyboard = UIStoryboard(name: "Main", bundle: nil) let viewController = storyboard.instantiateViewController(identifier: "View2") self.navigationController?.pushViewController(viewController, animated: true)
另外,你从View3返回View1时使用self.navigationController?.popToRootViewController(animated: true)是完全正确的,这个方法会弹出栈中所有非根控制器,直接回到View1,被弹出的控制器会在无其他强引用的情况下被系统回收。
内容的提问来源于stack exchange,提问作者Monrac
相关产品推荐
相关产品推荐

