Gizmodo
Gizmodo

Reputation: 3202

Proper way to remove UIViewController

I have a settingsController, which is a custom UINavigationController, that has to appear and disappear.

The XIB for it is in a storyboard and I have to keep track of it using var settingsController due to other house keeping purposes.

Main View Controller:

class MainViewController: UIViewController {

    var settingsController : MySettingsNavigationController?

    func settingsButtonPressed () {
        let storyboard = UIStoryboard(name: "Main Storyboard", bundle: nil)
        self.settingsController = storyboard.instantiateViewController(withIdentifier: "Settings Navigation Controller") as? MySettingsNavigationController
        self.settingsController!.transitioningDelegate = self
        self.settingsController!.modalPresentationStyle = .custom
        self.present(self.settingsController!, animated: true, completion: nil)
    }

    //Settings View Controller Transition Methods
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        let containerView = transitionContext.containerView
        let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)
        let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
        if(self.isSettingsPresenting == true) {
            toViewController!.view.alpha = 1;
            toViewController!.view.transform = CGAffineTransform(scaleX: 0.001, y: 0.001);
            toViewController!.view.center = self.settingsButton.center

            UIView.animate(withDuration: 0.5, delay: 0,
                           options: [.curveEaseIn], animations: { () -> Void in

                toViewController!.view.alpha = 1;
                toViewController!.view.transform = CGAffineTransform(scaleX: 1, y: 1);
                toViewController!.view.center = fromViewController!.view.center
                containerView.addSubview(toViewController!.view)

            }, completion: { (completed) -> Void in

                transitionContext.completeTransition(completed)

            })

        } else {
            UIView.animate(withDuration: 0.5, delay: 0,
                           options: [.curveEaseOut], animations: { () -> Void in

                fromViewController!.view.alpha = 0;
                fromViewController!.view.transform = CGAffineTransform(scaleX: 0.01, y: 0.01);
                fromViewController!.view.center = self.settingsButton.center

            }, completion: { (completed) -> Void in
                //Two lines below added later to test..
                fromViewController?.view.removeFromSuperview()
                fromViewController?.removeFromParentViewController()
                transitionContext.completeTransition(completed)
            })
        }
    }
}

Settings Navigation Controller:

class MySettingsNavigationController:  UINavigationController, UINavigationControllerDelegate
{
    .....

    func closeButtonPressed (_ sender: UIButton!) {
        self.dismiss(animated: true, completion: {
            //Tried removing self in here...
        })
    }
}

Issue:

When I bring up settingsController, and close it, memory allocated by settingsController is never released; Somehow, settingsController is not getting deallocated.

Note:

Somehow I do have to:

  1. Initiate the view controller from storyboard
  2. Use custom animation transition
  3. Not use a custom delegate (Since I cannot write a delegate to what is already a UINavigationControllerDelegate. This could have given me the chance to call back to parent, MainViewController that it's ready to get removed

Upvotes: 1

Views: 275

Answers (1)

ystack
ystack

Reputation: 1805

Somehow, settingsController is not getting deallocated

  • var settingsController looks like the probable culprit.
    Holding on a ViewController as a var object is highly discouraged.

I have to keep track of it using 'var settingsController' due to other house keeping purposes.

  • Evaluate utilising a sharedHelper- esque class that provides controller related attributes data or handles user interactions.
  • No function, except the settingsButtonPressed(which alone should be responsible for invoking settingsController), should be designed such that it requires an instance of settingsController to execute. The data required by such functions can be extracted by multiple ways like protocols, blocks, shared instances, etc.

Upvotes: 3

Related Questions