For the UIVIewController which is released and pushed on the navigation stack, memory allocated to it gets deallocated when view is popped.
But what about viewcontroller which is rootview controller i.e the first member on navigation stack which in turn bound to tab bar?
How to trace memory leak in it??
If it's never removed during the course of the app running, you don't need to worry about it leaking its member variables, because they'll always be required while the app is open.
When the app closes, the OS cleans up all the memory allocated to the app, even if it has leaked, so there's nothing to worry about.
For testing purpose I pushed the viewController from some dummy viewController...
Related
I'm working on an app where different view controllers get pushed and dismissed via dismissModalViewControllerAnimated.
I'm having some memory issues with the app just crashing after a while. Looking at the Leaks instrument, I see that my overall allocations keeps going up and up. Even after the viewcontroller is dismissed, memory does not go down.
Are there any obvious reasons for this? What is the simplest and easiest way to find out why my app is crashing? Thanks
POSSIBLE SOLUTIONS
I went through some trial and error as well as googling and made a few changes:
1) A delegate relationship may have been retaining the viewController, so I changed the object's delegate property to weak.
2) NSTimer's should be invalidated before dismissing viewController.
3) UIView animations may interfere with dealloc being called? You can use [view.layer removeAllAnimations] to end them before popping your viewController.
If your memory is not go down after the dismissModalViewControllerAnimated .. it means you are creating the Global Object of the ViewController And after dismissing you are not setting the Object = nil;
If you set nil then your memory goes down automatically.
I have a MainViewController, from which a new VideoPageViewController is presented modally.
In the ViewPageViewController, it will load a web page and launch the video, which is a heavy operation and sometimes causes memory warning. When it is ready to return to the MainViewController by dismissModalViewController, it says the MainViewController is already deallocated! The app thus crashes.
This happens sometimes, but not always.
Is there any exception handling I can take on it? Can I recreate the parent view controller? HELP!
Thanks
Just retain the MainViewController so it's not released when that happens.
You can probably do that in your application delegate, or in the class that owns it.
Remember to release it when/if you are done using it, so it's properly disposed of.
I've got next question - why my app dont waiting when i call
[navController popToRootViewControllerAnimated:NO];
... set new viewcontrollers here
I want:
1/ Kill all viewcontrollers by call popToRootViewControllerAnimated - with NO parameter - then i think i can immediately set new view controllers
2/ set new view controllers
But in my logs i see next:
call poptorootview controller
code after poptorootview
dealloc of views and controller (because i call poptorootview)
Why ? How can I detect that all views is killed and navigation controller is poping to root ?
Thanks,
A popped view controller will eventually be released (unless another object retains it), but the reference does not specify exactly when and how it is released. I wouldn't be surprised if it is not immediately released; the UIKit objects may use the view controller for the transition animation. It may be autoreleased not released, which may explain your logs. Also, I wouldn't be surprised inside UINavigationController multiple objects are retaining view controllers in the stack at the same time. Concisely speaking, there is no documented behavior about releasing popped view controllers. All we can be sure of is that it will be released at some point, as otherwise it will lead a memory leak.
Therefore you don't know when the view controllers are actually deallocated. Even if you find out it is subject to change without a notice. However, you can be sure when the view disappeared, using UINavigationController's delegate methods.
I have a navigation controller-based application with 5 view controller inside. When I push a view controller I allocate some memory and when I go back with popViewController my delloc() method is correctly called. I'm sure that the dealloc is called in the right way for every view controller I push and pop.
Nevertheless when I run the application with Instruments (Start with performance tools -> Object allocations, Leaks) there is a strange behavior for me.
When a view controller is pop the memory usage does not decrease, to be exact it does not decrease as expected:
when I start the application it use 950 KB, then I push the first view controller and the memory usage increase up to 1,56MB, finally I pop the view controller and the memory usage is now 1,55MB.
Is this behavior right?? I'm sure that every dealloc method is correctly called whenever I pop a view and the Leaks instrument does not show any memory leak.
I guess that the operating system is "retaining" in some way the view so that to second time I push the same view controller the loading process is much more fast...
Could someone confirm that this behavior is right?
Thanks
See this Screenshot from Instruments
This is as expected. The memory handling rules of "you are only accountable for objects you did alloc, copy etc. on" applies here as well.
When you push stuff on to the navigationController I assume you do it like this:
MyController *myCon = [[MyController alloc] init];
[self.navigationController pushViewController:myCon animated:YES];
[myCon release]; //You have alloc and release.
The navigationController is often handling a hierarchy where a user drills down a data set, and up again. By holding onto your controllers when memory is plenty is the navigationControllers way of saving having to instantiate the controller again 5 sec. later when the user taps "back". You can see this because dealloc never gets called, but viewWillAppear and viewDidAppear are called when you back up.
If memory is lacking the navigationController will start to release controllers on its stack.
But! make sure that going back and forward does not result in the viewControllers being instantiated again and again, this will make the memory footprint grow and there is a leak.
The navigationController should notice that it already has the viewController in its stack and simply display it.
You should be able to move through all the views and if they "fit" in memory, the app should never increase its memory footprint from here on out.
what are best pratices to reuse UIViewControllers? In many apps (including Apple's own examples: e.g. SQLiteBooks), UIViewControllers are allocated and initialized everytime, a UIViewController is pushed to the stack. This increases the use of memory with every new controller, because the objects stay in memory and aren't used again.
How to make it better?
This increases the use of memory with
every new controller, because the
objects stays in the memory and aren't
used again.
It should be released when the stack is popped though, as long as you have not got something else holding on to it. Check your dealloc methods are getting called.
Also if it is pushed to the stack, then you need to keep it around at least until it is popped (which automatically happens if you follow the standard patterns). So it is used again.
So following the standard pattern should already keep your memory usage as small as you can get away with.
This is what I do when creating a new viewcontroller and the memory is released when the view is removed from the window
MyViewController *mvc = [[[MyViewController alloc] initWithNibName:#"MyView" bundle:nil] autorelease];
[[self navigationController] pushViewController:mvc animated:YES];
Do you actually have a memory issue that you are trying to address or is this a case of premature optimization? I would say that unless there is a specific resource issue then the best practice would be to follow the standard view controller patterns.
Put a breakpoint in your view controller's dealloc function, and make sure it is called when you remove the view controller from the window. The memory shouldn't keep building up. If you're properly creating and autoreleasing your controllers (as LostInTransit shows above), the memory for each controller should be released when it is removed.
If you see that dealloc is not getting called, it means that somewhere in the app a reference to the view controller still exists.
Don't forget that a View Controller is not your view.
Views held by a view controller can unload, so view controllers themselves are very lightweight. If you want to keep the footprint really light you could nullify any other data the controller has allocated in viewDidUnload (mostly called when there's a memory warning - it's a 3.0 only thing though).
As noted mostly view controllers will be deallocated when you leave them (hit back) so there aren't generally that any hanging around anyway. But sometimes I find it handy to leave a reference around if I want to re-open that view in the same state the user left it (does not work between app launches).