How to Manage and Free Memory Through Viewcontrollers

How can I manage and free memory through ViewControllers

To remove viewController from memory you simply need to remove it from navigation stack. So when you call navigationController?.popViewController(animated: true) and back to previous view controller you already destroy that controller.

Then,

Here is my problem. When I log out, I want to create a new loginVC and clear all previous VC. So I have my cleanMemory function which set all the UIImage to nil

on logout it's good practice to stop all request but you don't need to do any changes to UI, because it takes some time and it doesn't need to "remove controller from memory". How to check if view controller completely removed from navigation stack? Simply write print statement in deinit func, compile code and go back from this view controller.

deinit {
print("ViewController deinit")
}

If this print works fine (you can see text in xcode console), you achieve the result - controller has been removed from navigation stack, but if there is no print result you probably forget to right manage your closures. For example

worker.cleanMemory(completionHandler: { (Value) in
...
})

this closure may hold your controller when your think that controller already deallocated and it means that your controller present somewhere in memory. To prevent these retain cycles you need to use [unowned self] of [weak self] (just google for this keywords, it's very easy to understand) like this:

// or you can use `[unowned self]`
worker.cleanMemory(completionHandler: { [weak self] (Value) in
guard let `self` = self else { return } // only for `weak` way
...
})

So, in this case there are nothing that can hold your controller alive after pop from navigation stack action or so.
These are simple rules that you should follow to write well managed code.

Managing Memory Usage VIewController Stack

A navigation stack keeps all the view controllers loaded in memory. That's integral to the way it works.

As Mr. Beardsley says, you can set up your view controllers to free their large data structures in your viewDidDisappear method (including setting image views to nil) and then reload them in viewWillAppear. If you make sure everything is cached to disk it should reload quickly.

To go beyond that, you'd need to forgo a navigation controller and create your own parent view controller that displayed a series of child view controllers. You could make the parent keep track of the navigation path the user followed and save state data for each view controller to disk, and then on the user pressing the back button, re-invoke the previous view controller and reconstitute it from it's saved state data. As long as everything is loaded from disk and not from the network you should be able to get near instant display of each screen when the user presses the back button.

This would require a fair amount of custom work on your part but shouldn't be that hard.

There are methods like 'transitionFromViewController:toViewController:duration:options:animations:completion:' that let you create custom transitions between child view controllers. You should be able to easily create whatever transition effect you want.

By saving a list of the view controllers that the user visited and a block of state data needed to recreate each view controller from disk you should be able to simulate a navigation stack while only having one child view controller active and in memory at a time.

Before going down this path, though, I would suggest looking at your user interface and seeing if there is a way to limit the depth to which the user can navigate. You could add some sort of limit to the depth of the user's navigation. The details would depend on your app design.

Keeping UIViewControllers in memory

Looking at the SDK, Apple makes both choices: UINavigationController keeps the whole stack of VCs below the top, while UIPageViewController aggressively releases any page except the current one.

This is an example of a "speed/space" trade. Precomputing and caching objects will be faster (once running) but occupy more memory. Releasing more aggressively and building (or rebuilding) will incur some run time cost but occupy less memory.

The question might also be an example optimizing too soon, or unnecessarily. For a handful of typical VCs the allocations are quick and the memory footprints are (ought to be) small. Changing approach will likely have insignificant impact on either speed or space.

I'd start with whichever way is simpler (probably allowing VCs to be released passively is simpler) and see if there's a demonstrable problem that needs solving.

How does ios manage ViewController's memory

Use Instruments to determine you are in fact having memory issues. If so, then yes, you might try deliberately setting images to nil when you navigate away from a view controller. But first you should ask yourself why you are having memory issues. A common mistake is to use big images to display in a small UIImageView; never do that. Always resize your images to be no bigger than needed for display. If you do, it's unlikely you'll experience any memory pressure.

Memory management ARC and view controllers

You are not getting a leak because you create a new controller and ARC will release this allocation for you.

But, it's better to create a @property for your new view controller.
and modify your i.e. implementation like :

@property (nonatomic, strong) ViewController *myViewController;

if (!_myViewController)
self.myViewController = [[ViewController alloc] init];

self.myViewController.delegate = self;
[self presentViewController:_myViewController animated:YES completion:nil];

Here, you have a lazy property and you don't create a new one ViewController after the first creation.
But, you need to pass your delegate (or any property) outside your test.

Furthermore, if you use your first implementation and add this controller in a subview of the current controller without property, this will work but you will get a leak.
I got this experience with the code below :

RootViewController

- (void)viewDidLoad
{
[super viewDidLoad];

ViewController *myViewController = [[ViewController alloc] init];
[self.view addSubview:myViewController.view];
}

myViewController will be add on the screen but released immediately without keeping any reference of the object, so if you add an action in 'ViewController`, your application will crash without explanation of XCode.

So, the correct way to write this without leak will be :

- (void)viewDidLoad
{
[super viewDidLoad];

if (!_myViewController)
self.myViewController = [[ViewController alloc] init];

[self.view addSubview:self.myViewController.view];
}

The answer is a bit longer and can be improved so don't hesitate !
Hope it's going to help some people.



Related Topics



Leave a reply



Submit