title: Modularize Slide Out Container ViewController
body: <p>In following the wonderful <a href="https://www.raywenderlich.com/78568/create-slide-out-navigation-panel-swift" rel="nofollow noreferrer">Ray Wenderlich tutorial</a>, I successfully created a Slide Out Container view in my app.</p>
  
  <p>I would like to incorporate this <code>ContainerViewController</code> in another place in my app, and so would like to modularize this as to not copy and paste code into another <code>ViewController</code>, however I am at a loss as to how to go about doing this.</p>
  
  <p>Here is the code from the tutorial:</p>
  
  <pre><code>import UIKit
  enum SlideOutState {
      case LeftPanelClosed
      case LeftPanelExpanded
  }
  
  class StudentContainerViewController: UIViewController {
  
      var centerNavigationController: UINavigationController!
      var centerViewController: SearchClassesTableViewController! // &lt;--- Need to change this
      var currentState: SlideOutState = .LeftPanelClosed
      var leftViewController: StudentSettingsTableViewController? // &lt;--- And this bad boy
      let centerPanelExpandedOffset: CGFloat = 60
  
      override func viewDidLoad() {
          super.viewDidLoad()
          centerViewController = UIStoryboard.centerViewController()
          centerViewController.delegate = self
  
          centerNavigationController = UINavigationController(rootViewController: centerViewController)
          view.addSubview(centerNavigationController.view)
          addChildViewController(centerNavigationController)
  
          centerNavigationController.didMove(toParentViewController: self)
  
          let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(_:)))
          centerNavigationController.view.addGestureRecognizer(panGestureRecognizer)
      }
  }
  
  private extension UIStoryboard {
      class func mainStoryboard() -&gt; UIStoryboard { return UIStoryboard(name: "Main", bundle: Bundle.main ) }
  
      class func leftViewController() -&gt; StudentSettingsTableViewController? {
          return mainStoryboard().instantiateViewController(withIdentifier: "StudentSettingsTableViewController") as? StudentSettingsTableViewController
      }
  
      class func centerViewController() -&gt; SearchClassesTableViewController? {
          return mainStoryboard().instantiateViewController(withIdentifier: "SearchClassesTableViewController") as? SearchClassesTableViewController
      }
  }
  
  extension StudentContainerViewController: CenterViewControllerDelegate {
      func toggleLeftPanel(){
          let notAlreadyExpanded = (currentState != .LeftPanelExpanded)
          if notAlreadyExpanded {
              addLeftPanelViewController()
          }
          animateLeftPanel(shouldExpand: notAlreadyExpanded)
      }
  
      func addLeftPanelViewController(){
          if leftViewController == nil {
              leftViewController = UIStoryboard.leftViewController()
              addChildSidePanelController(sidePanelController: leftViewController!)
          }
      }
  
      func addChildSidePanelController(sidePanelController: StudentSettingsTableViewController) {
          view.insertSubview(sidePanelController.view, at: 0)
          addChildViewController(sidePanelController)
          sidePanelController.didMove(toParentViewController: self)
      }
  
      func animateLeftPanel(shouldExpand: Bool){
          if shouldExpand {
              currentState = .LeftPanelExpanded
              animateCenterPanelXPosition(targetPosition: centerNavigationController.view.frame.width - centerPanelExpandedOffset)
          } else {
              animateCenterPanelXPosition(targetPosition: 0) {finished in
                  self.currentState = .LeftPanelClosed
                  self.leftViewController?.view.removeFromSuperview()
                  self.leftViewController = nil
              }
          }
      }
  
      func animateCenterPanelXPosition(targetPosition: CGFloat, completion: ((Bool) -&gt; Void)! = nil) {
          UIView.animate(withDuration: 0.5, delay: 0.0, options: UIViewAnimationOptions.curveEaseOut, animations: {
              self.centerNavigationController.view.frame.origin.x = targetPosition
          }, completion: completion)
      }
  
      func showShadowForCenterViewController(shouldShowShadow: Bool) {
          if shouldShowShadow {
              centerNavigationController.view.layer.shadowOpacity = 0.8
          } else {
              centerNavigationController.view.layer.shadowOpacity = 0.0
          }
      }
  }
  
  // MARK: Gesture Recognizer
  
  extension StudentContainerViewController {
      func handlePanGesture(_ recognizer: UIPanGestureRecognizer) -&gt; Void {
          let gestureIsDraggingFromLeftToRight = recognizer.velocity(in: view).x &gt; 0
  
          switch recognizer.state {
          case .began:
              if currentState == .LeftPanelClosed {
                  if gestureIsDraggingFromLeftToRight {
                      addLeftPanelViewController()
                  }
                  showShadowForCenterViewController(shouldShowShadow: true)
              }
          case .changed:
              if gestureIsDraggingFromLeftToRight || currentState == .LeftPanelExpanded {
                  recognizer.view!.center.x = recognizer.view!.center.x + recognizer.translation(in: view).x
                  recognizer.setTranslation(CGPoint.zero, in: view)
              }
          case .ended:
              if leftViewController != nil {
                  let hasMovedMoreThanHalfway = recognizer.view!.center.x &gt; view.bounds.size.width
                  animateLeftPanel(shouldExpand: hasMovedMoreThanHalfway)
              }
          default:
              break
          }
      }
  }
  </code></pre>
  
  <p>I need to be able to swap out the <code>center</code> and <code>leftViewController</code> properties. I made a superclass, and then set the <code>center</code> and <code>leftViewControllers</code> in the subclasses' <code>viewDidLoad</code>s (see below), however this did not work and the app broke in the extension of <code>UIStoryboard</code>, in the <code>mainStoryBoard</code> class func (also shown below)</p>
  
  <p>Superclass:</p>
  
  <pre><code>class SlideOutContainerViewController: UIViewController {
  
      var centerNavigationController: UINavigationController!
      var centerViewController: UIViewController?
      var currentState: SlideOutState = .LeftPanelClosed
      var leftViewController: UIViewController?
      let centerPanelExpandedOffset: CGFloat = 60
  
  
  ...same code as above...
  }
  </code></pre>
  
  <p>and subclass:</p>
  
  <pre><code>class StudentSlideOutContainerViewController: SlideOutContainerViewController {
  
  override func viewDidLoad() {
      super.viewDidLoad()
      centerViewController = SearchClassesTableViewController()
      leftViewController = StudentSettingsTableViewController()
  
          centerViewController = UIStoryboard.centerViewController() as! SearchClassesTableViewController
  //        centerViewController.delegate = self
  
      centerNavigationController = UINavigationController(rootViewController: centerViewController!)
      view.addSubview(centerNavigationController.view)
      addChildViewController(centerNavigationController)
  
      centerNavigationController.didMove(toParentViewController: self)
  
      let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(_:)))
      centerNavigationController.view.addGestureRecognizer(panGestureRecognizer)
  
      }
  }
  </code></pre>
  
  <p>Here's the stack trace: </p>
  
  <p><img src="https://i.imgur.com/aqRtTrO.png" alt="img1"></p>
  
  <p>And the line breaking with <code>EXC_BAD_ACCESS</code>:</p>
  
  <p><img src="https://i.imgur.com/c71zX57.png" alt="img2"></p>
  
  <p>I know it's a lot, and a long shot for any chances of solving but StackOverflow often has magical ways....</p>