You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MVVM模式下ViewController初始化viewModel后调用为nil崩溃怎么解决?

崩溃根因

你的崩溃核心是required init?(coder: NSCoder)初始化路径下没有给viewModel赋值:

  • 当你通过自定义的init(viewModel: SunCalendarViewModel)创建控制器时,viewModel会正常初始化,不会出现问题
  • 当控制器通过Storyboard/XIB、或者其他走NSCoder序列化的路径被创建时,系统会调用required init?(coder: NSCoder)而不是你的自定义构造方法,此时你仅调用了父类初始化,没有给viewModel赋值,隐式解包的可选值访问时就会触发崩溃。

修复方案

方案1:纯代码创建控制器

如果你的控制器完全不会通过Storyboard/XIB创建,直接把coder初始化路径标记为不可用即可:

required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented, use init(viewModel:) instead")
}

该方案会在错误调用coder初始化时抛出明确提示,避免出现viewModel隐式为nil的问题。

方案2:支持Storyboard/XIB创建

补充属性注入逻辑,兼容两种初始化路径:

private var viewModel: SunCalendarViewModel!

// 纯代码创建时调用
init(viewModel: SunCalendarViewModel) {
    self.viewModel = viewModel
    super.init(nibName: nil, bundle: nil)
}

// Storyboard/XIB创建时调用,后续需要手动注入viewModel
required init?(coder: NSCoder) {
    super.init(coder: coder)
}

// 提供注入方法,也可以直接将viewModel的访问权限改为internal供外部赋值
func config(viewModel: SunCalendarViewModel) {
    self.viewModel = viewModel
}

从Storyboard加载控制器后,在显示前手动注入viewModel即可:

let calendarVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SunCalendarVC") as! SunCalendarViewController
calendarVC.config(viewModel: SunCalendarViewModel())
// 后续执行push/present操作

MVVM初始化补充说明

MVVM没有强制要求实现configurator层,你可以用简单的工厂方法来统一管理控制器和ViewModel的绑定逻辑,避免初始化代码散落在业务侧:

enum SunCalendarModuleFactory {
    static func makeCalendarViewController() -> SunCalendarViewController {
        let viewModel = SunCalendarViewModel()
        return SunCalendarViewController(viewModel: viewModel)
    }
}

业务侧使用时直接调用工厂方法即可,不需要关心内部初始化细节。

内容的提问来源于stack exchange,提问作者MaryLitv21

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 00:24:05