Search code examples
iosswiftuisplitviewcontroller

One detail view for several UISplitViews


I have 3 UISplitViewControllers with different master views, but they have the same detail view. All of them are connected in Storyboard.

All UISplitViewControllers are nested in UITabBarViewController, so I switch between them via tab bar items.

The problem is, when I switch to another tab (another UISplitViewController) detail view disappears, I see only master view and a place for detail view is filled with dark gray (see pic). I don't want to reload detail view after switching, just leave it as is on the right side of the screen.

enter image description here

I'm not sure what code I need to provide, so if you need any, ask, I'll add it to question.

Thanks for any help!


Solution

  • Cause

    My first hypothesis was that the if you share a detail view controller between two distinct UISplitViewControllers, that correspond to two tabs of a UITabController, two separate detail view controllers are created. This is confirmed with a test project with this layout:

    enter image description here

    Root View Controller is a DetailViewController. When I put a breakpoint inside viewDidLoad(_:), it gets hit twice and printing shows that two different instances of DetailViewController are created:

    (lldb) po self
    <TestTabSplit.DetailTableViewController: 0x7fbd10eb9cd0>
    
    (lldb) po self
    <TestTabSplit.DetailTableViewController: 0x7fbd10ebc700>
    

    Solution

    Use a shared container view controller as the detail view controller of the two UISplitViewControllers.

    Your new storyboard layout will look like this:

    enter image description here

    1. Give your detail view controller (in this case a navigation controller), a Storyboard ID:

    enter image description here

    1. Next, in your app delegate, instantiate the detail view controller:

      // Add a variable to reference from elsewhere.
      var sharedNavigationController: UINavigationController!
      
      func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
          // Override point for customization after application launch.
      
          sharedNavigationController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("SharedID") as! UINavigationController
          return true
      }
      
    2. Finally, the container view controller, ContainerViewController, is just a subclass of UIViewController with the following contents:

      override func viewDidAppear(animated: Bool) {
          super.viewDidAppear(animated)
      
          let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
          let sharedNavigationController = appDelegate.sharedNavigationController
      
          addChildViewController(sharedNavigationController)
          sharedNavigationController.view.frame = view.bounds
          view.addSubview(sharedNavigationController.view)
          sharedNavigationController.didMoveToParentViewController(self)
      }
      

    With this setup, you'll find that the same detail view controller instance is share between tabs and modifications in one tab are persisted when you change to a new tab.