3
votes

I have two view controllers. On the first one I have a button, which shows the second one modally. Then, I close the second one by tapping a button on it (it goes down). For dismissing transition I have created a custom class which conforms to UIViewControllerAnimatedTransitioning, so I use a custom transition animation for view controllers (I needed a custom behaviour during the dismissing transition).

My question is the following: because of a custom transition that I use, is my view controller still get removed after the transition finishes or is it still there but off the screen? And if it is, will it affect the memory and how bad?

4

4 Answers

5
votes

You said:

is my view controller still get removed after the transition finishes or is it still there but off the screen?

There are two completely separate issues here.

First, there is a question of the view controller hierarchy. When you present a new view controller, the old view controller is always kept in the view controller hierarchy so that when you dismiss back to it, it will still be there. However, when you dismiss, the dismissed view controller will be removed from the view controller hierarchy and (unless you do something unusual, like keeping your own strong reference to it somewhere) it will be deallocated.

Second, there is a separate question of the view hierarchy. When presenting, the UIPresentationController dictates whether the presenting view controller's view remains in the view hierarchy or not. By default, it keeps it in the view hierarchy, but generally if doing a modal, full-screen "present", you'd specify a UIPresentationController subclass that tells it to remove the presenting view controller's view when the transition is done.


For example, when doing a custom modal "present" transition where the presented view controller's view is opaque and covers the whole screen, then your UIViewControllerTransitioningDelegate would not only supply the animation controllers, but also specify a presentation controller:

func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    return YourAnimationController(...)
}

func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    return YourAnimationController(...)
}

func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
    return PresentationController(presentedViewController: presented, presenting: presenting)
}

And that presentation controller might be fairly minimal, only telling it to remove the presenter's view:

class PresentationController: UIPresentationController {
    override var shouldRemovePresentersView: Bool { return true }
}
2
votes

The ViewController remains in the hierarchy.

You can confirm this by verifying the value of self.parentViewController property in the modal view controller.

Edit:

Will that view controller affect the memory?

Yes it will continue to perform all operations or activities (e.g: streaming audio, playing animation, running timers etc) in the parentViewController.

And if so, how can this situation be handled?

There are methods available in UIViewController class to detect when a ViewController will or is appeared / disappeared.
More specifically, following methods are at your disposal:

  1. viewWillAppear (Notifies the view controller that its view is about to be added to a view hierarchy)
  2. viewDidAppear (Notifies the view controller that its view was added to a view hierarchy)
  3. viewWillDisappear (Notifies the view controller that its view is about to be removed from a view hierarchy)
  4. viewDidDisappear (Notifies the view controller that its view was removed from a view hierarchy)

You can use viewWillAppear and viewDidAppear in parentViewController to start or resume such activities / operations.
And viewWillDisappear and viewDidDisappear to suspend or stop such activities / operations.

Hope this helps.

1
votes

I'm going assume that you are speaking about the view of your modal viewController staying in the window hierarchy - since you are asking if it is still there but off the screen, I believe you are talking about the view, and the controller, since controller is never on the screen.

And if you are asking about the view (which I assume that you are), calling completeTransition on transitionContext will remove it from the window hierarchy (so there is no need to call fromVC.view.removeFromSuperview()) - and by contract you are required to call completeTransition when the transition finishes in the UIViewControllerAnimatedTransitioning implementation.

You can confirm this behavior by checking the value of fromVC.view.superview before and after calling transitionContext.completeTransition:

UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: {
    fromVC.view.frame = endFrame
}) { (_) in
    print(">>> \(fromVC.view.superview)")
    transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
    print(">>> \(fromVC.view.superview)")
}
0
votes

Yes, the previous UIViewController remains there.
As described in Apple docs

viewControllerToPresent
The view controller to display over the current view controller’s content.