0

I am using a UINavigationController within my application. And I am trying my best to manage memory allocation. All my views do have a deinit method which are called/printed whenever an unWindSegue or navigationController.popViewController() is performed, given if there are no strong references.

When using performSegueWithIdentifer and override func prepare(for segue: UIStoryboardSegue, sender: Any?) the deinit method is NEVER called/used. I think this is due to the view I am transitioning to is not in memory.

Is it possible to have a conditional statement when performing a segue? As soon as my application is loaded, the HomeView is in memory. And I can also unwind to it which allows for the current view to be deallocated.

I have several views, and I wish to manage the memory as best as I can. Is is possible to peformSegueWithIdentifier once and always unwind to a view, once it is in memory, by using a conditional statement?

Pseudo code:

if navigationController.hasViewInMemory() {
   peformUnWindSegue()
} else {
   peformSegueWithIdentifier()
}

Or is there another way to go about it, which would allow for memory to be deallocated when performing a segue, regardless if the view is in memory or not? My application is based on time and most up to date information, and the last thing I wish is to return old/redundant data.

I am fairly new to memory management so apologises if this question seems a bit idiotic.

  • Swift automatically deallocates your instances when they are no longer needed, to free up resources. Swift handles the memory management of instances through automatic reference counting (ARC). Ensure you don't have a reference cycle or a strong reference you may have missed. This can happen easily when using any closures. https://docs.swift.org/swift-book/LanguageGuide/Deinitialization.html – Bryan May 29 '19 at 19:08
  • 1
    The navigation controller is managing a stack of view controllers. When you push or perform a segue, you are adding a new view controller instance to the stack. The others are still there, on the stack, so that you can pop or unwind back to them. It is up to you to track navigation in your app so that you know whether you want to go forward or back from where you are to where you want to be. You don't need to think about memory management, you need to think about how you want the navigation flow to work in your app. – Paulw11 May 29 '19 at 19:19
  • Unless you pop the views from the navigation stack the views will still be referenced by the navigation controller so the deinit method will not be called. – Bryan May 29 '19 at 19:25
  • @BryanWelter This is what I'm trying to do. Pop the previous `ViewController` when a new `ViewController` is presented however no luck. Any ideas on how to achieve this? – TheApprentice May 29 '19 at 20:58
  • @Paulw11 I completely understand, however, when my app is first loaded only the `HomeView` is in memory/in the stack. So I must perform a segue. However, the memory gradually builds up when I go from one view to another to another etc. How can I make it so I can pop the previous view controller when a new one is presented? – TheApprentice May 29 '19 at 20:59
  • 1
    In general you don't, otherwise how can the user navigate back through the stack? If you don't want the user to be able to back then you can update the navigation controllers `viewControllers` array directly to change the "history" in the navigation stack after you push the new view controller. You need to think about how you want the user to navigate through your app. Perhaps a navigation controller isn't the right approach? – Paulw11 May 29 '19 at 21:04
  • @Paulw11 I am using several storyboards. `Home`, `User` etc. are all different storyboards. I am performing segues with the use of a storyboard reference in some cases. These segues do not `deinit` when presenting the view controller. – TheApprentice May 29 '19 at 21:07
  • 1
    First, do you have a problem with running out of memory? If not, then probably don't worry. However, if you are pushing an ever deeper stack of view controllers on to your navigation controller then you probably have a structural issue with your app. Maybe a navigation controller isn't the right approach. Maybe you want a tabbed user interface, perhaps with each tab having its own navigation controller? Maybe you need to use a container view controller of your own and replace its content? – Paulw11 May 29 '19 at 21:11
  • I am not running out of memory, per say, memory does get `deinitalized` when users go back and helps to free up space. But if users went from `Home` > `User Profile` > `Search` memory can build up fairly quickly, due to not going back/poppingTheView. Hence why I would prefer if I could somehow `deinit` any/all views whenever a segue is performed. – TheApprentice May 29 '19 at 21:18
  • @Paulw11 The issue is always a new instance of a ViewController is created when using `performSegue` with identifier. I wish to combat this as memory can and will ramp up fairly quick. – TheApprentice May 29 '19 at 21:22
  • 1
    I understand your concern, but you are thinking about it at the wrong level. Don't think about how you free up memory. Think about how you navigate through your app. If you fix that then the view controllers will be released. The user goes to `Home->User Profile->Search` - What do they do from the search screen? Do they select some thing that you want to display? Does it make sense for the user to be moved out of the "user profile" path at that point? – Paulw11 May 29 '19 at 21:25
  • 1
    If so then when they select an item, use an unwind segue back to home. Pass the item they selected via the unwind segue (e.g. as a property on the source view controller). The unwind handler code can push the "display" view controller. Alternatively, when they select the item, manipulate the view controllers array so that the "previous" view controller is your, new, "display" view controller and pop the search view controller. – Paulw11 May 29 '19 at 21:27
  • 1
    Or push the new "display" view controller and again manipulate the view controllers array so that the previous view controller is the home view controller (i.e. remove the user profile and search view controllers from the history, allowing them to be released). Don't think about memory, think about the navigation path through your app – Paulw11 May 29 '19 at 21:28
  • @Paulw11 Luckily, the `User Profile` requires the user to go back and in essence `pop` the view controller. But if I went from `Home` -> `Search` -> `Settings` memory would increase. And if I just go from `Search` to `Settings` constantly, memory is allocated really quickly. To go to `Home` I do have a reference, and `unwindSegue` in all views. But this is only possible due to the fact it's already in memory. – TheApprentice May 29 '19 at 21:30
  • @Paulw11 I have tried to pushTheViewController many times but no luck, but I have taken your advice that when a segue is performed, to manipulate the array of view controllers and it has resolved the issue. Thank you ever so much! If you wish, leave it as the answer and I shall accept it. – TheApprentice May 29 '19 at 21:35
  • Why would you go search->settings->search-Settings->search->settings? You should structure it so that such a navigation isn't possible. Perhaps settings should be shown modally? You have a structural/navigation problem, not a memory problem. Stop thinking about memory use until you have a problem with your app crashing due to low memory; – Paulw11 May 29 '19 at 21:35
  • When dealing with the navigation stack try to avoid cycles. For instance the settings view would be an end point and you would need to pop the navigation stack after completing the task in it. Also make sure you understand the delegate pattern as you would use a custom delegate in order to store any settings set for the search in this scenario. The root to your problem may just be not knowing how and when to use the delegate pattern. – Bryan May 30 '19 at 15:31

0 Answers0