title: View/ViewController hierarchy and positioning issues
body: <p>I have a problem which I try to solve with 2 approaches. Both work to some extent, but then fail. The help with any of them will be highly appreciated. Also any other working approaches are welcome.</p>
  
  <p>This is the task that needs to be accomplished:</p>
  
  <p><em>I have an input component. For simplicity, let's say it contains only text field and send button. It is a view controller. The send button is another view controller that is embedded as a child view controller. The input component is then later embedded as a child view controller itself to some higher level container.
  This can't be changed and we have to take this as granted.
  The input controller should be clever enough to be able to display itself above the keyboard whenever its text field becomes first responder.</em></p>
  
  <p>So, <strong>the first approach</strong> is adding the input's component <code>contentView</code> as the text field's <code>inputAccessoryView</code>.</p>
  
  <pre><code>func textFieldDidBeginEditing(_ textField: UITextField) {
          // do some staff
  
          // This needs to be done, because in above-keyboard position the input component has another layout compared to when it's inactive
          contentView.layoutIfNeeded()
  
          // This is the actual adding itself to be displayed above the keyboard
          inputField.inputAccessoryView = contentView
  }
  </code></pre>
  
  <p>As far as I understand more staff happens under the hood including adding and removing child view controllers.
  Then, when the user taps return button or the send button, the following code is executed:</p>
  
  <pre><code>func textFieldShouldReturn(_ textField: UITextField) -&gt; Bool {
          textField.resignFirstResponder()
  
          return true
      }
  </code></pre>
  
  <p>which triggers the</p>
  
  <pre><code>func textFieldDidEndEditing(_ textField: UITextField) { 
          // We add contentView back where it was before and reset constraints
          view.addSubview(contentView)
  
          contentView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
          contentView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
          contentView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
      }
  </code></pre>
  
  <p>Hacky as hell, this code works. The only problem is that the view controller hierarchy seems to be corrupted (the input component is no longer displayed in view debugger, but the text field and button are on screen, so I was ok with that).</p>
  
  <p>Then I've found the corner case. When the user dismisses keyboard by tapping anywhere on screen, or when he/she activates another text field, the <code>textFieldShouldReturn</code> is not called, but the <code>textFieldDidEndEditing</code> is called.</p>
  
  <p>As a result, the <code>contentView</code> is removed from the <code>inputAccessoryView</code>, but it doesn't appear where it was before.</p>
  
  <p>Debugging revealed that its <code>superview</code> ends up being <code>nil</code>, which leads me to the conclusion, that iOS at some point removes it even though I've added it as a <code>view's</code> subview.
  If I add <code>contentView.removeFromSuperview()</code> before <code>view.addSubview(contentView)</code>, then the app crushes with this error message</p>
  
  <blockquote>
    <p>Thread 1: Exception: "child view
    controller:UICompatibilityInputViewController: 0x7fa13b2a3c00 should
    have parent view controller:(null) but actual parent
    is:UIInputWindowController: 0x7fa136045000"</p>
  </blockquote>
  
  <p>I don't understand how my code is guilty of this, so probably I do something that I am not supposed to from Apple's perspective.</p>
  
  <p>This is why I tried <strong>the second approach</strong>.
  This time I don't do anything with the <code>inputAccessoryView</code>. Instead I just modify the bottom constraint of the <code>contentView</code> to move up when keyboard is displayed:</p>
  
  <pre><code>func textFieldDidBeginEditing(_ textField: UITextField) {
  
  
          contentViewBottomConstraint.constant = // whatever the keyboard's height is
  
          UIView.animate(withDuration: viewModel.animationDurationForInputField,
                         delay: 0,
                         options: .curveEaseOut, animations: { [weak self] in
                          self?.view.layoutIfNeeded()
          })
      }
  </code></pre>
  
  <p>and to hide</p>
  
  <pre><code>func textFieldDidEndEditing(_ textField: UITextField) {
  
          contentViewBottomConstraint.constant = 0
  
  
  
      UIView.animate(withDuration: viewModel.animationDurationForInputField,
                     delay: 0,
                     options: .curveEaseOut, animations: { [weak self] in
                      self?.view.layoutIfNeeded()
      })
  }
  </code></pre>
  
  <p>This works like a charm and actually this should be the correct approach without messing around with <code>inputAccessoryView</code> and child-parent relationships of the view controllers.</p>
  
  <p>But, the problems begin when this input component is embedded into the detail part of the master/detail controller. On iPad, the detail part takes around half of the screen. So is the width of our input component. And when the keyboard is displayed, the input component is pushed up, but it's width remains the same - half of the screen.</p>
  
  <p>To make it full screen, I get the reference to the top window, deactivate old leading and trailing constraints and add new one - between top window and <code>contentView</code>.</p>
  
  <pre><code>guard let keyWindow = UIApplication.shared.keyWindow else { return }
  contentViewBottomConstraint.constant = viewModel.bottomOffsetForInputField
  NSLayoutConstraint.deactivate(originalContentViewConstraints)
  contentViewToKeyboardLeadingConstraint = contentView.leadingAnchor.constraint(equalTo: keyWindow.leadingAnchor)
  contentViewToKeyboardLeadingConstraint?.isActive = true
  contentViewToKeyboardTrailingConstraint = contentView.trailingAnchor.constraint(equalTo: keyWindow.trailingAnchor)
  contentViewToKeyboardTrailingConstraint?.isActive = true
  </code></pre>
  
  <p>And it does become full screen, only half of it is not visible, because it is in the detail part of the master/detail, so it is overlapped by the master part.
  And I am not able to bring it to front.</p>
  
  <p>I tried adding it as subview to the window - crash because child/parent relationships are broken.</p>
  
  <p>Moving subview to front - no effect (obviously, but I had to try).</p>
  
  <p>Changing zPosition - no effect.</p>
  
  <p>So, at the moment I've run out of ideas.
  This is a very corner case, but I need to make it work because it (master/detail) is the actual layout in the application.</p>
  
  <p>Thank you in advance for any help.</p>