优化prepareForSegue与UINavigationController结合的实现方式?
优化
prepareForSegue的优雅实现方案 针对你遇到的prepareForSegue写法优化问题,结合你给出的思路,我来分享一个既安全又简洁的最优实现方案:
问题背景
你有两类自定义视图控制器,各自需要专属的配置方法:
class ProfileViewController: UIViewController { func configure(profile: Profile) { // ProfileViewController专属配置逻辑 } } class SettingsViewController: UIViewController { func configure(settings: Settings) { // SettingsViewController专属配置逻辑 } }
在通过Segue跳转模态视图时,你尝试了两种prepareForSegue的标准写法,但都存在不够优雅的地方,想要结合两者优点的写法却无法编译。
两种标准写法的局限
1. 嵌套Switch写法
这种写法逻辑清晰,但嵌套层级深,后续新增视图控制器时会让代码嵌套更复杂,维护成本上升:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { switch segue.destination { case let nav as UINavigationController: switch nav.topViewController { case let pvc as ProfileViewController: pvc.configure(profile: profile) case let svc as SettingsViewController: svc.configure(settings: settings) default: break } default: break } }
2. Where条件写法
这种写法避免了嵌套,但需要使用强制类型转换(as!),存在潜在的类型安全风险,而且条件判断和类型转换分离,代码不够紧凑:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { switch segue.destination { case let nav as UINavigationController where nav.topViewController is ProfileViewController: (nav.topViewController as! ProfileViewController).configure(profile: profile) case let nav as UINavigationController where nav.topViewController is SettingsViewController: (nav.topViewController as! SettingsViewController).configure(settings: settings) default: break } }
最优实现:扩展+元组Switch
你尝试的结合写法无法编译,是因为Swift的where子句不支持直接在条件里绑定可选类型转换的结果。不过我们可以通过扩展UIStoryboardSegue来简化导航控制器顶层视图控制器的获取,再结合元组Switch实现类型安全且简洁的代码:
第一步:扩展UIStoryboardSegue
先给Segue添加一个计算属性,快速获取导航控制器的顶层视图控制器(如果目标是导航控制器的话):
extension UIStoryboardSegue { var destinationNavTopViewController: UIViewController? { return (destination as? UINavigationController)?.topViewController } }
第二步:优化prepareForSegue写法
通过元组同时匹配原始目标控制器和导航顶层控制器,既支持直接跳转视图控制器,也支持嵌套在导航控制器里的情况,而且类型转换是安全的可选绑定,无需强制解包:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { switch (segue.destination, segue.destinationNavTopViewController) { case let (_, pvc as ProfileViewController): pvc.configure(profile: profile) case let (_, svc as SettingsViewController): svc.configure(settings: settings) case let (ovc as OtherViewController, _): ovc.configure(/* 对应配置参数 */) default: break } }
这种写法的核心优点:
- 无嵌套层级,代码扁平化,可读性极强
- 类型转换安全,彻底避免
as!带来的崩溃风险 - 同时兼容直接跳转视图控制器和通过导航控制器跳转的场景
- 新增视图控制器时只需添加新的case分支,扩展性极佳
内容的提问来源于stack exchange,提问作者Ashley Mills
相关产品推荐
相关产品推荐

