Keeping UIViewControllers in memory - ios

I am building an iOS app with one of those "hamburger menu" type drawers that open up to a list of options of the left. Like this:
Each time you click on an item, for example "settings" it loads a new viewcontroller and displays it on the main view controller. Now, the question I'm wondering is whether or not I should be releasing the viewcontrollers each time a new item in the menu is clicked.
For example:
You are viewing Inbox
You click Settings
I release InboxViewController and alloc init the SettingsViewController
I make the SettingsViewController the main viewcontroller
I'd like to keep all the viewcontrollers in memory, because I think it would provide for a more smooth transition from one to the next if it was previously allocated, instead of having to wait each time to allocate it.
I am using ARC
Is this bad practice? I might have 6-7 viewcontrollers 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.

If you consider what you're doing, it's really no different than a UITabBarController. The views don't load until they are viewed the first time, but then are kept "alive" indefinitely. I would think as long as you keep the number of loaded view controllers reasonable (single digits) you'll probably be fine, with the one caveat that if they are all doing some intensive processing/loading/etc., it could become problematic.

I don't necessarily think keeping all the ViewControllers in memory is a good thing, unless the View contains objects that take a long time to fetch (i.e. opening a UIDocument or from a NSURLRequest).
Hope that helps!

Related

Reduce app memory footprint

I have a very image heavy app. (And before you say: no I can't reduce the amount of images). This means that there are a lot of UIImageViews going on in my storyboard files.
The overall structure of the app is something like this:
The Content View Controller is the one that is image heavy and at any one time up to around 12 of them can be in memory at any one time due to the page view controller.
I have been getting memory warnings and leaks (from my investigations these are separate unrelated events) and the system has terminated the app on occasion.
Aside from writing my own implementation of UIPageViewController what can I do to reduce memory footprint?
I don't think you need to create you own implementation of UIPageViewController, you just need to use UIPageViewControllerDelegate/DataSource and UIViewController wisely.
For instance UIViewController has a method that is triggered during memory warnings, are you getting rid of heavy images on VCs that are not visible inside that method?

Properly dismissing (or "destructing") views in Swift

I'm concerned about tiny lags and memory issues, and how they might scale.
My app is programmed using Swift and I've been doing everything in the app programmatically, including page navigation using presentViewController and dismissViewControllerAnimated.
Note: the app's page hierarchy can be several pages deep and each page contains quite a number of images.
I started experiencing tiny, occasional, lags which could appear more often on older phones; I can only test on iPhone 6 right now. I also noticed a small increase in memory while navigating through pages. Of course the memory level on the app (as observed in XCode) is not the same as opening the app in fresh state compared to going back to the first page after navigating through tens of pages, I'm expecting the memory level comparison could come at least close.
Now, my question: is there a proper way to "destruct" my page views (including UIKit elements, images, etc.) when such page view is dismissed?
I assume that by "page" you mean a viewController: There is no way to directly destroy objects with ARC (automatic reference counting), as they are deallocated automatically when their strong reference counter is zero. Since you experience unusual memory increase, it might be that you have some strong reference cycles in your code. Make sure to declare properties as weak wherever necessary. You should check out the ARC Guide for detailed explanation. I hope this helps.

iOS Memory usage keep increasing

I'm new to iOS development.
I'm building a simple bus schedule app that makes a HTTP request, parse XML, and display/save data. I have four table view controllers and two view controllers.
When I start the app, Xcode memory report tells me that its memory usage is ~18MB, which is weird since it's just a simple app. I've looked at similar apps on the app store but they were all less than 10MB. Since it's a bus schedule app, I have it make new requests every 30 seconds to update the time. I noticed that each time I change view to look at another schedule, the memory usage increases and it may go up to 50MB or more.
I looked at Xcode's instrument and it looked like there was no leaks. I also looked at allocations and it looked like live bytes kept increasing every time I switched views.
I am kinda stuck from what to do from here. Can anyone guide me please? Thanks in advance.
Use Heapshot to find memory creep. (see: bbum blog)
Basically, their method is to run the Instruments allocate tool, take a heapshot, run an iteration of your code and another heapshot, repeating 3 or 4 times. This will indicate memory that is allocated and not released during the iterations.
In this case, take a heapshot (called something different now) between downloads.
To figure out the results, disclose to see the individual allocations.
If you need to see where retains, releases, and autoreleases occur for an object use Instruments:
Run in Instruments, in Allocations set "Record reference counts" to on (you will have to stop recording to set the option). Allow the problem code to run, stop recording, then search for the object of interest. After that, you'll need to drill down and you will be able to see where all retains, releases and autoreleases occurred.
First, take a look at heap shots as #Zaph suggested. Well worth your while in terms of seeing what's being allocated and not released.
Another technique I use is to use instruments filtering options to filter the display for just the classes in my app. Then, I look for classes which have unusual number's of living instances. For example, most view controllers usually have only one active instance. If there are more, then something is retaining them. Blocks and notification listeners are often the cause.
In your example screen shot, I noticed two things that I would investigate.
Firstly, you have 365 living core animations taking some 30M. Not sure why, but worth thinking about.
Secondly, near the bottom, I noticed 166 table view cell scroll views. Sounds like a lot. I can't see how many living table view controllers you have, but I'm wondering if they are not reallocing. Filtering this list will help establish what's not being dealloc'd.
Finally, leaks can be useful in finding issues, but most of the time what we would regard as a leak looks ok to instruments. So, looking at memory and numbers of allocated instances is a far better guide to finding where things are not being dealloc'd.
Hard to say without any code, but it looks like you have a retain cycle somewhere.
Try to add a dealloc method to the view controllers and make sure that you enter it whenever the view controller disappears.
You say that you make a new request every 30 seconds. If you use a timer with the view controller as a target, the timer has a strong reference to the view controller and vice versa. You have to invalidate the timer when your view controller disappears.

App is taking too much memory until a crash ! (iPhone)

I am quite beginner in development and I'm making an application that have about 150 ViewControllers ! Each one have a UIImageView.
I've been doing a bit of testing, and after a use the app for a while on the iPhone itself, it Crashes when I keep viewing the ViewControllers.
I've been analyzing this in instruments, and I have no leaks, however my memory allocation just goes up and up and when I keep viewing the ViewControllers on my iPhone the usage just goes up and up until a crash.
I think it's clear that it's crashing because the app is simply taking up too much memory.
So could any one explain how to release viewControllers in order to free up the memory so there will be no crash
Thanks in advance !
The first question you need to ask yourself is why do you need 150 ViewControllers.
Do you want to present 150 different images?
If so, then multiple ViewControllers is not the way to go. You probably need to use a UIScrollView that will contain your images (not all of them at once, of course. Use lazy loading).
What's probably happening in your case is that you call "pushViewController" each time you need to display a new ViewController, but this doesn't release the previous ViewController. It simply stacks all of the previous ViewControllers and retains their pointers.
You see, the way Navigation Controllers work is that they have an array of view controllers. Every time you present a new view controller, it is added at the end of the array. When you click on "Back" or call "popViewController" the last item of the array is removed (and then released automatically from memory).
See this and this questions to learn how to create a UIScrollView to scroll images.

How do I reload a view from the storyboard (or otherwise manage low memory condition)?

In developing my current app, I ran into some issues that I eventually traced back to a low memory warning. Part of the low memory is coming from my (liberal) use of UIWebViews, which are apparently consuming a lot of memory.
I didn't think this would be an issue, since a view that isn't currently visible should just vanish when the low memory warning is thrown, unfortunately it turns out that anything connected to the UITabBarController remains in the heirarchy and doesn't release. By manually releasing (and then recreating in viewWillAppear) the views, I make things work decently. But it doesn't completely solve the memory warning issue.
So what I need to do is manually release the view -- and the large amount of memory that winds up connected to it -- and then restore it. Since I don't want to build it programmatically (that's what IB is for!), I need to somehow reload it from storyboard.
Or, alternatively, I'm being an idiot and there's something really obvious to make my life easy.
After more experimentation, it turns out that on the one hand, my understanding of view life cycles was slightly flawed, and on the other my experiments were tainted by having accidentally let zombie objects on.
Views will, in fact, unload their contents in a low memory condition and reload them later -- that's part of what 'viewDidLoad' and 'viewDidUnload' are designed for! Putting init code in them, as some tutorials I read did, was a major error. That init code should go in the designated initializer -- even if that can be annoying to figure out which initializer is designated.

Resources