0

this is probably a newbie question...

I'm trying to reduce the amount of memory usage in my iPhone app.

I have an UIViewController with a set of buttons. When the user taps any of them, the app takes him to a new screen (new UIViewController).

Should I create them on demand ([[MyUIViewController alloc] initWithNibName:@"MyUIViewController" bundle:nil];), or should I have all these UIViewControllers as @propertys in the "main" controller, and create them only the first time? (check if they are nil).

I noticed (with Instruments) that, following the first approach, the used memory (Live bytes) increases on push but does not decrease when pulling the controller, and so on every time I press a button.

Furthermore, does that also applies to UITableViews, where I push another UIViewController in tableView:didSelectRowAtIndexPath: method?

Thank you in advance.

EDIT: I'm using ARC

sonxurxo
  • 5,648
  • 2
  • 23
  • 33
  • Generally you should just create controllers on-demand, as you need them, rather than up-front. No need to waste precious memory. – Rob Jul 07 '12 at 17:24

5 Answers5

1

You said:

I noticed (with Instruments) that, following the first approach, the used memory (Live bytes) increases on push but does not decrease when pulling the controller, and so on every time I press a button.

So when you go from VC1 to VC2 are you saying that the memory usage goes up significantly, but isn't dropping as you return to VC1? Have you checked your code for leaks? First, run it through static analyzer (shift+command+B), which can identify some of the most egregious mistakes. You should have zero warnings.

Second, run your code through Instruments via the profiler to identify any leaks. See the "Finding Leaks" section of the Instruments User Guide.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • No warnings with the Analyzer :( – sonxurxo Jul 07 '12 at 17:41
  • Also, by the way, just because you popped a view, depending upon what you've got going on, it's _possible_ that iOS might do some clever caching in the background (e.g. `UIImage`'s `imageNamed`) that might not release everything. So don't be too distressed if you don't get back exactly where you started. Just make sure your app isn't leaking. – Rob Jul 07 '12 at 17:42
  • It seems to have 2 leaks (malloc 48 bytes, libsystem_c.dylib). I think it has nothing to do with my code... The question is that after 2 or 3 minutes playing intensively with the app, it easily reaches 15 or 20 MB, and a memory warning is received. I set to nil all properties in viewDidUnload in *every* VC, so I don't know what else I can do... – sonxurxo Jul 07 '12 at 17:53
  • @sonxurxo I suspect it's unrelated, but you should look at what you clear in `viewDidUnload` vs `dealloc`. The former is called after `didReceiveMemoryWarning` situations. So I generally nil my `IBOutlet`s there (and if I'm doing caching, my caches, too), but I do most of my non-IBOutlet ivar/property cleanup in `dealloc`. Also, the iOS 6 beta notes have some interesting comments re `viewDidUnload` that you might want to look at (but which we're precluded from discussing publicly). – Rob Jul 07 '12 at 18:10
  • would you enter this chat room (http://chat.stackoverflow.com/rooms/13561/should-i-create-an-uiviewcontroller-every-time-i-want-to-push-it) and discuss it there? TIA – sonxurxo Jul 07 '12 at 18:21
0

Keeping them around and reusing them will keep your apps base memory at a higher level, but will probably increase the performance as these will not need to be recreated on demand.

That being said, the performance of pushing a new view controller is not very bad to begin with (unless you are doing something wrong) so just create them on demand.

If the old VC memory is not being released when popped, you might have a retain cycle somewhere. Look for any delegate code you may have written that is not getting cleared on the dismissal of the view.

coneybeare
  • 33,113
  • 21
  • 131
  • 183
  • I don't think I have any retain cycle (at least, my "second" VC does not keep any reference to the first one). But so, why the memory usage only grows, and does not go, for instance, from 1.1MB -> 1.5MB -> 1.1MB -> 1.5MB ->.... when I push->pop->push->pop.... my second VC? – sonxurxo Jul 07 '12 at 17:29
  • It doesn't only grow... here you show a scenario where the memory decreases correctly when popped here. This is different from what you described in the question of "the used memory does not decrease". So which one is it? – coneybeare Jul 07 '12 at 17:33
  • The scenario is: when I push a VC, Live bytes grow. When I press back button (pop), the Live Bytes stays more or less the same. When I push again, it grows again. When I pop again, it stays. So it's continuously growing – sonxurxo Jul 07 '12 at 17:36
  • Then I don't understand your 1.1 -> 1.5 -> 1.1 -> 1.5 question – coneybeare Jul 07 '12 at 17:37
  • That's what I expected the behavior to be, but it isn't (maybe I didn't explain myself clearly, sorry about that) – sonxurxo Jul 07 '12 at 17:38
0

Generally, a UIViewController should be fairly light on memory. It's the UIView objects that you can save the most memory on, by ensuring you're familiar with the view life-cycle and that you let the views get cleaned up (by not holding references to them anywhere outside the view controller's view property and by setting any other view references to nil in viewDidUnload). There's a good answer here about how to use viewDidUnload.

Having said that, so long as it's not very heavyweight to create your view controllers, it's probably better to re-create them whenever needed. This is not so much for memory reasons, but for simplicity. So unless you need to keep references to them in properties for other reasons keep it simple and use less code - just create them as-needed.

Community
  • 1
  • 1
jhabbott
  • 18,461
  • 9
  • 58
  • 95
0

This is probably a newbie answer, so please take it with a grain of salt.

In this scenario, I never worry about implementing my view controllers in code. I use the storyboard to create the initial view controller and embed it in a navigation controller. Then, I create subsequent view controllers and link them to the appropriate parts of the initial controller's view through named segues (by control-dragging). I think that by using this technique, a view controller down the chain will only be instantiated once its segue has fired. I'm sure Apple has optimized the heck out of this and so I'm confident that by using the storyboard I'll conserve more memory than by trying to fiddle around with things in code.

Nathan Jones
  • 108
  • 1
  • 7
0

After chatting with @RobertRyan here (I suppose the link will remain), he gave me the solution: the problem was I was having a retaining cycle in my VC2 (please take a look at the chat so I don't rewrite everything here). Thank you very much @RobertRyan!

Community
  • 1
  • 1
sonxurxo
  • 5,648
  • 2
  • 23
  • 33