1

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
Caleb Kleveter
  • 11,170
  • 8
  • 62
  • 92
Gizmodo
  • 3,151
  • 7
  • 45
  • 92
  • 1
    Does it work if you set `settingsController` to be `weak`? – Caleb Kleveter Mar 03 '17 at 19:56
  • I tried making it weak. Somehow, it's still not getting removed properly. If I log out settingsController, after the animation is completed, it still shows that it's alive.. – Gizmodo Mar 03 '17 at 19:57
  • 1
    Can you use a protocol to let the `MainViewController` know the `SettingsViewController` wants to dismiss, and dismissing `Settings` from there, and setting `settingsController` to nil in the completion? – creeperspeak Mar 03 '17 at 19:58
  • The only way I know how to do this is make a SettingsViewController Delegate. But Swift yells at me saying there's already a UINavigationControllerDelegate. – Gizmodo Mar 03 '17 at 20:00
  • Is using a protocol possible with SettingsViewController? – Gizmodo Mar 03 '17 at 20:12

1 Answers1

3

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.
ystack
  • 1,785
  • 12
  • 23
  • For example, if you have a settings screen that comes and goes, how would u see if its present at different occasions without a var ? – Gizmodo Mar 03 '17 at 20:18
  • You can fire a `NSNotification` on presentation & dismissal of the _settings screen_. An interested object(probably a `ViewController`) can be an observer of this notification & perform related actions thereafter. – ystack Mar 03 '17 at 20:21
  • I guess the easy way out of above is to write a delegate in to settingsController. However, since it's a UINavigationController, swift yells saying that it already has a delegate: UINavigationControllerDelegate. Is there a way to still do that? – Gizmodo Mar 03 '17 at 20:34
  • 1
    I'm not sure whether it would be an easy way out without the knowledge of implementation details. You can consider extending the `UINavigationControllerDelegate` protocol to provide the desired additional functionality. Check out: http://stackoverflow.com/questions/732701/how-to-extend-protocols-delegates-in-objective-c – ystack Mar 03 '17 at 20:39