views:

320

answers:

2

Background: I have a tab bar controller which currently contains 4 tabs. 3 of the tabs are navigation controllers which display a hierarchy of table views for viewing, editing, and creating data. The data is generally NSStrings that are taken from the user and stored in a global variable (data needs to be accessed from multiple views in the hierarchy, as well as multiple tabs).

Problem I have noticed that my app uses quite a bit of memory as soon as it starts (~11mb). However, as I scroll through the table views and use the nav controller to access more table views and edit some data, the memory usage quickly goes up to nearly 20mb. The worst part is that popping out of the detail view controllers does not cause the memory usage to decrease. It will hover around 20-21mb, and if I repeat the process I seem to get higher and higher memory usage. I have tested my app in Leaks and I have solved all issues there. I suspect that my inactive view controllers are still sitting in memory, even as they are not currently displayed. Is there any way to release unneeded view controllers in a navigation controller's hierarchy, or even the inactive view controllers from the tab bar? I have been reading Apple's docs and they strongly suggest implementing didReceiveMemoryWarning: and applicationDidReceiveMemoryWarning: in view controllers and the app delegate alike. I really don't know where to start with those methods. What controllers can I release and how do they get recreated? I assume that I'm responsible for that, but I would like to be sure.

Note that I have not yet gotten my app to terminate due to low memory usage, but enough repititions of data entry (lot of view controller pushing and popping) will cause it to slow to a crawl.

+3  A: 

If repeatedly viewing the same screens leads to higher and higher memory usage, you have a leak. The fact that Leaks doesn't detect it doesn't mean you have no leaks. Even a garbage collected program can leak if you hold onto data you shouldn't be holding onto.

Pull up Instruments with Object Allocations template and see what's eating the majority of your memory. Look at what's still in memory that shouldn't be. If you think your view controllers should be getting out of memory, put an NSLog() in their -dealloc and confirm that they really are getting out of memory.

You should implement didReceiveMemoryWarning in your view controllers, and Apple gives guidence on how to implement it in Memory Management of Nib Objects. At the very least you should implement a logging statement in didReceiveMemoryWarning so you know if you're receiving warnings. But that's unlikely the actual problem. Failure to implement this method doesn't cause memory leaks, it just prevents you from releasing memory as fast as you could in low-memory situations.

Are you following the #1 rule of Cocoa Memory management: Thou shalt use accessors? Do not mess with your instance variables directly, and most memory management issues go away.

Rob Napier
A: 

Actually, in iPhone OS 3.0+ UIViewController subclasses should usually just implement viewDidUnload instead of didReceiveMemoryWarning. It automatically gets called in low memory systems if the current view controller's view is not being displayed. You should release things like IBOutlets there, which will cause the actual views to release, which is fine since if they end up being displayed again viewDidLoad will be called first.

didReceiveMemoryWarning is still appropriate in some cases if you have some sort of memory you can shed even when the UIViewController is being displayed (like caches).

Louis Gerbarg