如何向UITabBarController的moreNavigationController中的ViewController注入依赖?
Nice setup with the NeedsContainer protocol—it’s a clean way to flag which view controllers need access to your Core Data stack. Let’s tackle how to handle dependency injection for the view controllers that end up in the moreNavigationController (the system-managed navigation controller for overflow tabs).
Core Idea
The moreNavigationController doesn’t create new instances of your view controllers—it references the same ones you added to your tab bar controller’s viewControllers array. So we can cover both upfront and dynamic scenarios with two key steps:
- Pre-inject the container into all eligible view controllers when setting up the tab bar.
- Listen for navigation events in the
moreNavigationController(and all other navigation controllers) to handle dynamically pushed view controllers.
Step 1: Refine Your NeedsContainer Protocol
First, make sure your protocol is set up to allow injection (mark the property as get set and use AnyObject to restrict it to classes):
protocol NeedsContainer: AnyObject { var persistentContainer: NSPersistentContainer! { get set } }
Step 2: Implement Injection in Your Tab Bar Controller Subclass
In your UITabBarController subclass (let’s call it MainTabBarController), you’ll hold the persistent container and handle injection logic.
class MainTabBarController: UITabBarController { // Initialize your Core Data container let persistentContainer = NSPersistentContainer(name: "YourDataModel") override func viewDidLoad() { super.viewDidLoad() // Load Core Data stores first persistentContainer.loadPersistentStores { description, error in if let error = error { fatalError("Core Data load failed: \(error.localizedDescription)") } } // Inject container into all initial tab view controllers preInjectContainerIntoTabs() // Set up delegates to handle dynamic navigation (including moreNavigationController) setupNavigationDelegates() } }
Step 3: Pre-Inject the Container
Add a helper method to recursively inject the container into all eligible view controllers (including those nested in UINavigationControllers):
private extension MainTabBarController { func preInjectContainerIntoTabs() { guard let tabViewControllers = viewControllers else { return } for vc in tabViewControllers { injectContainer(into: vc) } } func injectContainer(into viewController: UIViewController) { // Inject if the view controller conforms to NeedsContainer if let needsContainerVC = viewController as? NeedsContainer, needsContainerVC.persistentContainer == nil { needsContainerVC.persistentContainer = persistentContainer } // Recursively handle child view controllers for childVC in viewController.children { injectContainer(into: childVC) } // Handle navigation controller stacks if let navVC = viewController as? UINavigationController { navVC.viewControllers.forEach { injectContainer(into: $0) } } } }
Step 4: Handle Dynamic Navigation Events
When users tap overflow tabs or push new view controllers in the moreNavigationController, we need to catch those events and inject the container. Make your tab bar controller conform to UINavigationControllerDelegate:
extension MainTabBarController: UINavigationControllerDelegate { private func setupNavigationDelegates() { // Set delegate for all tab navigation controllers viewControllers?.compactMap { $0 as? UINavigationController }.forEach { $0.delegate = self } // Set delegate for the system's moreNavigationController moreNavigationController.delegate = self } func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) { // Inject container into the newly shown view controller (and its children) injectContainer(into: viewController) } }
Key Notes
- No Duplicate Injection: The check
needsContainerVC.persistentContainer == nilensures we don’t overwrite an already injected container (optional but good practice). - Nested Controllers: The recursive
injectContainer(into:)method covers view controllers nested in navigation controllers, tab bar controllers, or custom container view controllers. - System Safety: The
moreNavigationControlleris managed by UIKit, but setting its delegate is safe—we’re just listening for navigation events, not modifying its core behavior.
This approach ensures every view controller that conforms to NeedsContainer gets the persistent container, whether it’s in a regular tab or the overflow more menu.
内容的提问来源于stack exchange,提问作者SimonTheDiver

