title: ViewController Containment with Subclassing
body: <p>in an attempt to up my "getting away from massive view controllers" I am trying some stuff with view controller containment.</p>
  
  <p>Here's what I want:</p>
  
  <ul>
  <li>have a base class with a scroll view and an embedded stack view</li>
  <li>inherit from that class with an implementation of my desired scene</li>
  <li>being able to add child view controllers as needed to my implementation</li>
  </ul>
  
  <p>I expect something like this:</p>
  
  <p><a href="https://i.stack.imgur.com/FN6hT.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/FN6hT.png" alt="enter image description here"></a></p>
  
  <p>Here's the code I am trying to achieve this with:</p>
  
  <pre><code>import UIKit
  
  /**
  Base class
  */
  class PrototypeStackViewController: UIViewController {
  
      private let scrollView: UIScrollView = {
          let s = UIScrollView()
          s.translatesAutoresizingMaskIntoConstraints = false
          s.contentMode = .scaleToFill
          return s
      }()
  
      private let stackView: UIStackView = {
          let s = UIStackView()
          s.translatesAutoresizingMaskIntoConstraints = false
          s.axis = .vertical
          s.alignment = .fill
          s.distribution = .fill
          s.contentMode = .scaleToFill
          return s
      }()
  
      override func loadView() {
          view = UIView()
          view.backgroundColor = .systemGray
  
          view.addSubview(scrollView)
          scrollView.addSubview(stackView)
  
          let  nstraint = stackView.heightAnchor.constraint(equalTo: scrollView.frameLayoutGuide.heightAnchor)
          stackViewHeightConstraint.priority = .defaultLow
  
          NSLayoutConstraint.activate([
              scrollView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
              scrollView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
              scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
              scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
  
              stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
              stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
              stackView.topAnchor.constraint(equalTo: scrollView.topAnchor),
              stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
  
              stackViewHeightConstraint
          ])
      }
  
      override func viewDidLoad() {
          super.viewDidLoad()
      }
  
      func add(child: UIViewController) {
          addChild(child)
          stackView.addArrangedSubview(child.view)
          child.didMove(toParent: self)
      }
  
      func remove(child: UIViewController) {
          guard child.parent != nil else { return }
  
          child.willMove(toParent: nil)
          stackView.removeArrangedSubview(child.view)
          child.view.removeFromSuperview()
          child.removeFromParent()
      }
  }
  
  /**
  Implementation of my scene
  */
  class PrototypeContainmentViewController: PrototypeStackViewController {
  
      lazy var topViewController: PrototypeSubViewController = {
          let t = PrototypeSubViewController()
          t.view.backgroundColor = .systemRed
          t.label.text = "Top View Controller"
          return t
      }()
  
      lazy var centerViewController: PrototypeSubViewController = {
          let t = PrototypeSubViewController()
          t.view.backgroundColor = .systemGreen
          t.label.text = "Center View Controller"
          return t
      }()
  
      lazy var bottomViewController: PrototypeSubViewController = {
          let t = PrototypeSubViewController()
          t.view.backgroundColor = .systemBlue
          t.label.text = "Bottom View Controller"
          return t
      }()
  
      override func loadView() {
          super.loadView()
  
          add(child: topViewController)
          add(child: centerViewController)
          add(child: bottomViewController)
      }
  
      override func viewDidLoad() {
          super.viewDidLoad()
  
      }
  }
  
  /**
  Sample View Controller
  */
  class PrototypeSubViewController: UIViewController {
  
      lazy var label: UILabel = {
          let l = UILabel()
          l.translatesAutoresizingMaskIntoConstraints = false
          return l
      }()
  
      override func loadView() {
          view = UIView()
          view.backgroundColor = .systemRed
  
          view.addSubview(label)
  
          NSLayoutConstraint.activate([
              label.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 12),
              label.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -12),
              label.centerYAnchor.constraint(equalTo: view.centerYAnchor),
              label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
          ])
      }
      override func viewDidLoad() {
          super.viewDidLoad()
      }
  }
  
  </code></pre>
  
  <p>Here's what I get:</p>
  
  <p><a href="https://i.stack.imgur.com/mlOMH.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/mlOMH.png" alt="enter image description here"></a></p>
  
  <p>If you look close, you can even see the "Bottom View Controller" label – but on top the green center view controller.</p>
  
  <p>I am missing something here in my love-hate-relation with auto layout, that much is for sure...</p>