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
相关产品推荐
相关产品推荐

