Dismiss ViewController after transition to release memory
Asked Answered
S

4

16

I want to free up memory my ViewController used after dismissing it. I use the following code to present the new ViewController and dismiss the old one:

let sB: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newVC: UIViewController = sB.instantiateViewController(withIdentifier: "MyVC")
self.present(newVC, animated: true, completion: { x in
    oldVC.dismiss(animated: false, completion: { _ in //oldVC: variable keeping track of currently visible view controller
        print("done")
    })
})

This code successfully presents newVC and prints done after dismissing oldVC. However, my memory still stays as high as it was when having oldVC on screen.
What am I doing wrong?

FYI

  • I am using ENSwiftSideMenu
    • Since I didn't get it to work in a different way, all my ViewControllers are a subclass of ENSideMenuNavigationController
  • I am getting console warnings about detached views and views not being in the window hierarchy
  • for all ViewControllers, both presentingViewController and presentedViewController are nil
Sacaton answered 23/9, 2016 at 12:56 Comment(13)
What is the reference of the oldVC ?Evidential
What do you mean by "reference"? It is a global variable that is set to self in each ViewController's viewWillAppear(_:) method. Hence, it is of type `UIViewControllerSacaton
Try to add this line deinit { debugPrintln("Clean") }Evidential
Add to the oldVC's code?Sacaton
yes in this case we could see when oldVC will be really dealcoatedEvidential
Not printing anything…Sacaton
Probably you have strong reference to this viewControllerEvidential
What's that mean?Sacaton
blog.reigndesign.com/blog/…Evidential
Let us continue this discussion in chat.Sacaton
have you tried to make oldVcC to weak? weak var OldVC = selfHolmquist
Yes. It already is a weak variableSacaton
To reduce memory foot prints this can help you - #26921727Kc
P
6

Check the following issues:

  1. You should dismiss the old ViewController before present a new ViewController, or you will dismiss the new one at the same time.
  2. Swift using ARC to manage memory. The oldVC is not released since some objects have a strong reference to it. Make an example, i have a ViewController with a variable tableView. The tableView will release when the ViewController released. But at the same time if you link it to another ViewController that is not released, the tableView will not release although the previous ViewController is released.

Solution:

  1. Present a UINavigationController and using setViewControllers to manage the transition of your ViewControllers.
  2. Remove the useless reference of the oldVC

If you really do not understand. You can search:

  1. ARC
  2. UIViewController transition
Provincial answered 27/9, 2016 at 11:6 Comment(14)
When dismissing before presenting I'm left with a blank screen.Sacaton
@LinusG. Because both the old and new controllers are dismissed after you call the dismiss function.Provincial
So what am I gonna do?Sacaton
@LinusG. My suggestion is to put both old and new controllers to a UINavigationController to arrange your transitions. If you do want use present. You can try dismiss the old controller without an animation and present the controller in its completion closure.Provincial
The latter is exactly what I did. I will try with the nav though.Sacaton
@LinusG. Try this, not use oldVC to dismiss. self.dismiss(animated: false, completion: { _ in //oldVC: variable keeping track of currently visible view controller self.present(newVC, animated: true, completion: { x in }) print("done") })Provincial
Let us continue this discussion in chat.Sacaton
@LinusG. Do you fix your problem?Provincial
Unfortunately not yet, nope.Sacaton
@LinusG. Please see my code first. codeload.github.com/Moonsownner/Test1/zip/masterProvincial
@LinusG. Hi, i`m back, do you get through the problem?Provincial
So do you still want fix the same problem? What is it going on now?Provincial
Yes of course. Any other ideas how to regarding my FYI section in the post?Sacaton
Let`s chat in chat.stackoverflow.com/rooms/124426/…Provincial
F
3

Your oldVC will not be deallocated, since your newVC (and any UIViewController) keeps by default a strong reference to its presentingViewController - the controller that presented it. If this was not the case, you would never be able to safely dismiss your newVC without disturbing the view hierarchy.

As far as your specific problem is concerned, in order to deallocate your old view controller, I would suggest dismissing the oldVC first and then display your newVC from another ViewController, earlier in the stack (could be the UIApplication shared().keyWindow?.rootViewController)

Fini answered 27/9, 2016 at 10:17 Comment(3)
Well I am getting a warning saying sth. about the view not being in window hierarchy. Until now I wasn't able to fix that issue and since it never caused any problems I didn't really have to.Sacaton
@LinusG. It is indeed issued as a warning (although in my experience it can result in errors)Fini
Presenting from rootViewController leaves me w/ a blank screen :(Sacaton
A
3

I had the same issue for UINavigationController's push/pop. @spassas is right about the strong reference which is the reason your newVC is not deallocated. You should look at the newVC closely.

In my case (written in Objective-C) there was another view controller referenced as a private property of the pushed view controller (your newVC):

EventActionSheetViewController* actionSheet;

That actionSheet had a strong reference to the pushed view controller (newVC) as its delegate:

@property (nonatomic) id<EventActionSheetDelegate> delegate;

I've been checking my app's memory and found that the pushed view controller wasn't deallocated after being popped by the navigation controller. After a few hours I changed the strong reference to weak and it worked out:

@property (nonatomic, weak) id<EventActionSheetDelegate> delegate;

The problem was that my pushed view controller and its EvenetActionSheetViewController had strong references to each other and somehow did not let each other deallocate.

I recommend you to check if your newVC has similar strong references loops and change them to weak where possible. In Swift use weak let or weak var instead of let/var. Hope this will help you find the bug.

Abscise answered 27/9, 2016 at 11:7 Comment(3)
I did change my declaration to weak var but that doesn't change anything apparently.Sacaton
@LinusG. I think we need to see some code of the newVC to helpAbscise
What do you need?Sacaton
A
1

Try replacing your code with the following:

    let appDel = UIApplication.shared.delegate as! AppDelegate
    let sB: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
    let newVC = sB.instantiateViewController(withIdentifier: "MyVC")
    appDel.window?.rootViewController = newVC
    appDel.window?.makeKeyAndVisible()

Hope this works !

EDIT : You can also check that the old View Controller is being de-initialized by adding the following code to all the View Controllers :

    deinit {
        debugPrint("Name_Of_View_Controller deinitialized...")
    }

EDIT 2:

If you want to preserve the flow of presentation in view controllers and you only want to dismiss the last view controller, i.e.,

In a transition : masterVC -> oldVC -> newVC

And after the transition from oldVC to newVC, you want to return back to masterVC, freeing up memory by oldVC. You can pass the masterVC reference to the oldVC and achieve what you want to as following:

if(masterVC != nil) {
         oldVC.dismiss(animated: false, completion: {
            let sB: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
            let newVC = sB.instantiateViewController(withIdentifier: "vc2")
            self.masterVC!.present(newVC, animated: false, completion: {
                print("done")
            })
        })
}

This works for the case you stated.

Agio answered 2/10, 2016 at 8:20 Comment(1)
Which one is not working for you? The first one, or the second one? And do you have any strong references in the oldVC ?Agio

© 2022 - 2024 — McMap. All rights reserved.