VIP架构下点击侧边菜单修改ViewController中UIImageView图片报nil错如何解决
错误原因分析
- 无效的ViewController实例:你在
changeTheme方法内新创建的JokeGenerateController实例,没有走完整的视图加载流程,xib/Storyboard关联的backGroundImageIBOutlet还处于未初始化的nil状态,调用changeBackground方法时给nil的ImageView赋值,触发隐式解包崩溃。且这个新创建的实例并不是当前展示在界面上的控制器,就算赋值成功也不会产生界面变化。 - 图片资源强制解包风险:
UIImage(named: "duck")!如果项目中不存在对应名称的图片资源,会直接解包nil触发崩溃。
修复方案
方案1:复用Router持有的现有VC实例(符合VIP架构规范)
VIP架构中Router本身会持有当前ViewController的弱引用,不需要重新创建实例,直接调用现有实例的方法即可,修改Router的changeTheme逻辑:
func changeTheme(theme: Themes) { guard Themes.Dark == theme, // 取Router持有的当前VC实例,不要新创建 let targetVC = self.viewController as? JokeGenerateController, // 可选校验图片,避免强制解包崩溃 let duckImage = UIImage(named: "duck") else { return } targetVC.changeBackground(image: duckImage) }
方案2:通知中心实现跨组件通知(解耦可选方案)
如果侧边菜单和目标VC不属于同一个路由层级,可以通过通知传递主题切换事件:
- 在
JokeGenerateController的viewDidLoad中添加通知监听:
override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(handleThemeChange(_:)), name: NSNotification.Name("ChangeThemeNotification"), object: nil) } @objc func handleThemeChange(_ notification: Notification) { guard let theme = notification.object as? Themes, theme == .Dark, let duckImage = UIImage(named: "duck") else { return } changeBackground(image: duckImage) }
- Router的
changeTheme方法改为发送通知:
func changeTheme(theme: Themes) { NotificationCenter.default.post(name: NSNotification.Name("ChangeThemeNotification"), object: theme) }
额外优化点
给changeBackground方法添加可选校验,避免IBOutlet意外为空时触发崩溃:
func changeBackground(image: UIImage) { guard let backGroundImage = backGroundImage else { return } backGroundImage.image = image print("hey") }
内容的提问来源于stack exchange,提问作者huseyin
相关产品推荐
相关产品推荐

