以导航控制器为初始视图控制器的依赖注入问题解决
问题描述
我查遍了状态共享相关的依赖注入教程,都没提到导航控制器作为初始视图控制器的场景。我尝试在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
相关产品推荐
相关产品推荐

