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

VIPER架构下ViewController的Presenter报nil错误的原因及解决方法

VIPER架构下ViewController中Presenter为nil的原因与解决方案

核心问题根因

你遇到的Presenter为nil问题,本质是实际显示的ViewController实例没有经过Router的依赖注入流程,或者注入的依赖因引用规则错误被系统回收,结合贴出的代码,常见触发场景如下:

  • 多实例导致的依赖错配
    iOS 13及以上版本默认采用SceneDelegate生命周期管理App窗口,如果你将窗口、根控制器的初始化逻辑写在AppDelegate的启动方法中,系统会在SceneDelegate流程中自动创建独立的UIWindow和根控制器实例。这个自动创建的实例没有经过Router的createMovieController流程,自然没有完成Presenter的赋值;你在Router里看到Presenter非空的打印,只是那个从未被显示的、仅存在于局部作用域的控制器实例的状态。
  • 引用修饰符违背VIPER依赖规则
    Router方法中的presenter是局部初始化的临时常量,如果ViewController中的presenter属性被错误添加了weak修饰,方法执行结束后没有强引用链路持有这个临时创建的Presenter,ARC会立刻回收Presenter实例,weak修饰的属性就会被自动置为nil。
    标准VIPER架构的引用规则为:
    • View 对 Presenter:强引用
    • Presenter 对 View:弱引用
    • Presenter 对 Interactor:强引用
    • Presenter 对 Router:强引用
    • Interactor 对 Presenter:弱引用(回调代理场景)
      一旦引用关系颠倒,就会出现依赖意外释放的问题。
  • 实例链路断裂
    如果App启动流程中,没有将wireframe.createMovieController()返回的控制器设置为导航控制器的根控制器,反而在其他位置手动初始化了一个新的MovieVC实例用于显示,新实例没有任何依赖注入流程,presenter自然会保持默认的nil状态。

排查与解决方法

  • 修正生命周期入口
    将窗口、根控制器的初始化逻辑从AppDelegate迁移到SceneDelegate的scene(_:willConnectTo:options:)方法中,删除AppDelegate中重复的窗口初始化代码,保证整个App只有一个UIWindow实例,显示的根控制器完全来自Router的创建流程。
  • 修正引用修饰符
    检查ViewController中presenter属性的声明,移除多余的weak修饰,确保是默认的强引用关系;同步校验所有模块的引用链路,避免强引用环或意外释放。
  • 验证实例一致性
    在Router的createMovieController方法返回前,打印控制器实例的内存地址;在ViewController的viewDidLoad方法中打印自身的内存地址,两个地址完全一致说明实例链路正确。如果地址不一致,说明流程中额外创建了控制器实例,修正初始化逻辑即可。
  • 定位赋值失效点
    在view.presenter = presenter赋值的位置,打印赋值后的Presenter内存地址;在ViewController读取presenter的位置(比如viewDidLoad中),打印当前读取到的presenter地址。如果赋值后地址正常,但读取时为nil,优先排查引用修饰符错误的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.27 16:36:03