在prepare for segue方法中初始化ViewController是否为最佳实践?附自定义初始化器疑问
关于
prepare(for:sender:)中初始化ViewController的实践与你的代码设计分析 一、在prepare(for:sender:)中初始化ViewController是不是良好实践?
答案是不是。原因很直观:
- 当你通过segue(不管是storyboard配置还是代码触发的segue)跳转时,系统已经自动完成了目标ViewController的实例化工作,你可以通过
segue.destination直接获取到这个已创建好的实例。 - 要是你在
prepare(for:sender:)里自己初始化一个新的ViewController并试图替换segue的目标,会彻底破坏segue的原生流程——既会忽略你在storyboard/xib里配置的布局、约束等设置,还可能导致导航栈异常,比如跳转后页面不符合预期、内存泄漏等问题。
正确的做法是:在prepare(for:sender:)中拿到目标VC的实例,然后给它的公开属性赋值,传递所需的数据或依赖。举个例子:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "ShowNewProfile" { guard let newProfileVC = segue.destination as? NewProfileVC, let selectedUser = sender as? Users else { return } // 给已实例化的VC传递必要依赖 newProfileVC.setup(with: selectedUser, coreDataStack: appCoreDataStack) } }
二、你的NewProfileVC与NewProfileViewModel初始化设计分析
你为这两个类设计的自定义初始化器,非常利于编写单元测试,这是个很棒的实践!
优点:
- 依赖关系清晰:初始化器明确声明了VC和ViewModel需要的依赖(
Users实例、CoreDataStack),避免了隐式依赖(比如全局单例),让代码的逻辑依赖一目了然。 - 测试灵活性高:在测试时,你可以轻松传入测试用的
Users对象(比如模拟的测试用户数据)和CoreDataStack的测试实例(比如内存型Core Data栈,不会操作真实数据库),后续还能扩展让VC支持直接注入Mock版的NewProfileViewModel,进一步提升测试的可控性。
可选优化点:
如果想让VC的测试粒度更细(比如单独测试VC的UI逻辑,不用依赖真实ViewModel),可以给NewProfileVC新增一个支持注入ViewModel的初始化器:
// 保留原有初始化器,用于正常业务流程 init(for user: Users, with coreDataStack: CoreDataStack) { self.user = user self.viewModel = NewProfileViewModel(for: user, with: coreDataStack) super.init(nibName: nil, bundle: nil) } // 新增初始化器,用于测试时注入Mock ViewModel init(user: Users, viewModel: NewProfileViewModel) { self.user = user self.viewModel = viewModel super.init(nibName: nil, bundle: nil) } // 必须实现的required初始化器 required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
这样在测试VC时,你可以创建NewProfileViewModel的Mock子类,模拟各种方法的返回值,专注测试VC的UI响应逻辑。
内容的提问来源于stack exchange,提问作者J. Doe
相关产品推荐
相关产品推荐

