-3

I have several view controllers (UIViewController). Each view controller has its own storyboard. And I want the app to call deinit when it transitions from one view controller to another. But it won't.

The app starts with HomeViewController. And it will transition to SelectViewController when the user taps a button (UIButton).

class HomeViewController: BasicViewController {
    @IBAction func selectTapped(_ sender: UIButton) {
        let storyboard = UIStoryboard(name:"Select",bundle:nil)
        let controller = storyboard.instantiateViewController(withIdentifier: "SelectView") as! UINavigationController
        let viewController = controller.topViewController as! SelectViewController
        self.navigationController?.pushViewController(viewController, animated: true)    
    }

    deinit {
        print("HOME HAS BEEN REMOVED FROM MEMORY")
    }
}

The app never calls deinit when it leaves HomeViewController. I wonder if that's because it's pushing a view controller? If I set the view controller as follows, the app will crash. What am I doing wrong? I have never done it with different storyboards. Thanks.

class HomeViewController: BasicViewController {
    @IBAction func selectTapped(_ sender: UIButton) {
        let storyboard = UIStoryboard(name:"Select",bundle:nil)
        let viewController = storyboard.instantiateViewController(withIdentifier: "SelectView") as! SelectViewController
        self.navigationController?.setViewControllers([viewController], animated: true)  
    }
}

UPDATE 1

I guess it's just the following.

@IBAction func selectTapped(_ sender: UIButton) {
    let storyboard = UIStoryboard(name:"Select",bundle:nil)
    let controller = storyboard.instantiateViewController(withIdentifier: "SelectView") as! UINavigationController
    self.present(controller, animated: true, completion: nil)
}

UPDATE 2 I also clear the view controller stack when SelectViewController appears as follows.

override func viewWillAppear(_ animated:Bool) {
    super.viewWillAppear(animated)

    var navigationArray = self.navigationController?.viewControllers
    navigationArray?.removeAll()
}
El Tomato
  • 6,479
  • 6
  • 46
  • 75
  • 1
    You can use a storyboard reference from one storyboard to the next - no need to do it in code – Ashley Mills May 08 '17 at 07:35
  • @Ashley Mills Thanks for the tip. You can transition from one view controller to another without writing code when they have its own storyboard? How? – El Tomato May 08 '17 at 07:44
  • 1
    Drag a "storyboard reference" onto your first storyboard - set it's values corresponding to the view controller on your second storyboard. Drag out a link from your button to the reference. – Ashley Mills May 08 '17 at 08:12
  • Hmm... I didn't know anything about Storyboard References. Thanks a lot. – El Tomato May 08 '17 at 08:18
  • Using the storyboard reference works to make the app transition from one view controller to another. But I would also like to know how to do it in code. – El Tomato May 08 '17 at 08:29

2 Answers2

1

Actually, It is not about storyboards. As per the Apple's documentation, "deinit" method gets automatically called when an object is deallocated from memory, not when a view controller is pushed from current one.

When you push "SelectViewController" from "HomeViewController", instance of "HomeViewController" does not deallocated from memory, hence deinit method does not called.

Here is a link to Apple's Documentation for Deinitialization. Alternatively, you can use "viewDidDisappear" method of the view controller to perform an operation if it satisfies your need.

Jigaroza287
  • 635
  • 5
  • 13
  • Okay. Thanks. So how do I remove HomeViewController from memory? – El Tomato May 08 '17 at 08:02
  • @ElTomato You should not remove this view controller from the memory. – Mannopson May 08 '17 at 09:43
  • You can remove object of view controller from array of navigation but according to me that would be an illogical thing. Can you tell me what is your exact requirement so that I can give you the proper solution if possible? – Jigaroza287 May 08 '17 at 09:45
1

From your code snippet, I understand that you expect deinit is called after pushViewController. But, by calling pushViewController, your navigation controller pushes your HomeViewContoller to navigation stack, which means navigation controller holds strong reference to your HomeViewController object. So, deinit is not called. If you don't need HomeViewController, you have to manually remove it from navigation stack w/in SelectViewController. See this how. How to remove a specific view controller from uinavigationcontroller stack?

In SelectViewController,

override func viewDidAppear(_ animated: Bool) {
  super.viewDidAppear(animated)
  let allControllers = NSMutableArray(array: navigationController!.viewControllers)
  allControllers.removeObject(at: allControllers.count - 2)
  self.navigationController!.setViewControllers(allControllers as [AnyObject] as! [UIViewController], animated: false)
}
Community
  • 1
  • 1
beshio
  • 794
  • 2
  • 7
  • 17
  • Thanks. But that's probably not going to solve my deinit issue since I even call remove all view controllers from the stack with SelectViewController's viewWillAppear. – El Tomato May 08 '17 at 08:56
  • Hmm.. that's strange since I'm doing as I wrote, but I remove w/in viewDidAppear. I understand viewWillAppear of the next controller is called before viewDidDisappear of the previous controller. You can easily check it. – beshio May 08 '17 at 09:03