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

以导航控制器为初始视图控制器的依赖注入问题解决

问题描述

我查遍了状态共享相关的依赖注入教程,都没提到导航控制器作为初始视图控制器的场景。我尝试在AppDelegate里注入BidDetailsController,但因为HomeViewController被嵌入在导航控制器中,注入没有成功,导致使用BidDetailsController内的值时一直出现nil错误。

我原来的AppDelegate代码:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // 导航栏样式配置
    let navigationBarAppearance = UINavigationBarAppearance()
    navigationBarAppearance.configureWithTransparentBackground()
    navigationBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
    navigationBarAppearance.backgroundColor = #colorLiteral(red: 0.9686274529, green: 0.78039217, blue: 0.3450980484, alpha: 1)
    UINavigationBar.appearance().tintColor = .white
    
    UINavigationBar.appearance().standardAppearance = navigationBarAppearance
    UINavigationBar.appearance().compactAppearance = navigationBarAppearance
    UINavigationBar.appearance().scrollEdgeAppearance = navigationBarAppearance
    
    // 尝试依赖注入,但无效
    let homeViewController = HomeViewController()
    homeViewController.bidDetailsController = BidDetailsController()
    
    return true
}

相关视图控制器代码:

class HomeViewController: UIViewController {
    
    var bidDetailsController: BidDetailsController!

    override func viewDidLoad() {
        super.viewDidLoad()
        title = "HOME"
        // 这里重新实例化会覆盖注入的对象
        bidDetailsController = BidDetailsController()
    }
    
    @IBAction func menuBtnTapped(_ sender: Any) {
        print("Show Menu")
    }
    
    @IBAction func newBidBtnTapped(_ sender: Any) {
        performSegue(withIdentifier: "homeToInfoSegue", sender: self)
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let infoViewController = segue.destination as? InfoViewController {
            infoViewController.bidDetailsController = bidDetailsController
        }
    }
    
}
class BidDetailsController {
    var exampleVariableOne = String()
    var exampleVariableTwo = Bool()
}
解决方案

问题出在两个核心点:

  • 你在AppDelegate里新建了一个HomeViewController实例,但实际运行时用的是Storyboard中导航控制器自带的HomeViewController实例,两者不是同一个对象,所以注入完全无效。
  • HomeViewController的viewDidLoad里重新实例化了BidDetailsController,就算之前注入成功,也会被覆盖成新的实例。

按照以下步骤修改即可解决:

1. 修正AppDelegate中的注入逻辑

从Storyboard中获取实际运行的初始导航控制器,再拿到它的根视图控制器(也就是你的HomeViewController),然后注入共享的BidDetailsController实例:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // 保留原有导航栏样式配置代码
    let navigationBarAppearance = UINavigationBarAppearance()
    navigationBarAppearance.configureWithTransparentBackground()
    navigationBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
    navigationBarAppearance.backgroundColor = #colorLiteral(red: 0.9686274529, green: 0.78039217, blue: 0.3450980484, alpha: 1)
    UINavigationBar.appearance().tintColor = .white
    
    UINavigationBar.appearance().standardAppearance = navigationBarAppearance
    UINavigationBar.appearance().compactAppearance = navigationBarAppearance
    UINavigationBar.appearance().scrollEdgeAppearance = navigationBarAppearance
    
    // 正确的依赖注入逻辑
    guard let window = UIApplication.shared.windows.first,
          let navController = window.rootViewController as? UINavigationController,
          let homeVC = navController.rootViewController as? HomeViewController else {
        return true
    }
    // 创建全局共享的BidDetailsController实例
    let sharedBidController = BidDetailsController()
    homeVC.bidDetailsController = sharedBidController
    
    return true
}

2. 移除HomeViewController中的重复实例化代码

删除viewDidLoad里重新创建BidDetailsController的代码,避免覆盖注入的共享实例:

class HomeViewController: UIViewController {
    
    var bidDetailsController: BidDetailsController!

    override func viewDidLoad() {
        super.viewDidLoad()
        title = "HOME"
        // 移除这行代码:bidDetailsController = BidDetailsController()
    }
    
    // 其余方法保持不变
}

3. 验证状态共享

现在HomeViewController里的bidDetailsController是从AppDelegate注入的全局共享实例,通过prepare(for:sender:)传递给InfoViewController后,两个页面操作的是同一个BidDetailsController对象,状态会自动保持同步。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 20:36:18