Search code examples
iosswiftuiviewcontrollersegue

iOS10: How to avoid memory leaks in a segue circle


I have 4 scenes in my project, and page1 can segue(type is show) to page2, then can segue to page3, then to page4, then back to page1.

You understand that in 1 second from my storyboard:

enter image description here

The class of controller of these four scene is ViewController:

import UIKit

class ViewController: UIViewController {

    static var count: Int = 1

    var id = count

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        ViewController.count += 1
        print("ViewController#\(id) inited.")
    }

    deinit {
        print("ViewController#\(id) deinited.")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        print("ViewController#\(id) loaded.")
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        print("ViewController#\(id) appeared.")
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        print("ViewController#\(id) disappeared.")
    }

}

Then after I finished the segue circle(page1 > page2 > page3 > page4 > page1), it outputs:

ViewController#1 inited.
ViewController#1 loaded.
ViewController#1 appeared.
ViewController#2 inited.
ViewController#2 loaded.
ViewController#2 appeared.
ViewController#1 disappeared.
ViewController#3 inited.
ViewController#3 loaded.
ViewController#3 appeared.
ViewController#2 disappeared.
ViewController#4 inited.
ViewController#4 loaded.
ViewController#4 appeared.
ViewController#3 disappeared.
ViewController#5 inited.
ViewController#5 loaded.
ViewController#5 appeared.
ViewController#4 disappeared.

That's not what I wanted. I think there are 5 ViewControllers in my heap(because no deinit called). Indeed, we just need 1 ViewController which is to control page1. What should I do to destroy 4 useless ViewController in the heap of my App?


Solution

  • Presenting/Dismissing

    NOTE:

    If you are working with a navigation controller, you might want to check my answer about Pushing/Popping.


    The action of "Back To Page1" in the fourth View Controller-, should be similar to:

    @IBAction func backToPage01Tapped(_ sender: Any) {
        presentingViewController?.presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil)
    }
    

    Note that the reason of why the number of presentingViewController are three, because it's the number of previous View Controllers for the fourth one.

    If you have only two previous View Controllers, then you must chain backwards twice and call dismiss from two View Controllers back:

    presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil)
    

    and so on...