All,
I am running into some performance/memory issues when using several ChildViewControllers
in my ParentViewController
. Here is my situation: I have a ParentViewController
with a dynamic number of ChildViewControllers
- some times as many as 20. They are contained in a UIScrollView
, and are paged through. I'm running into problems when I have several on the page (I'm only loading the first two, then building the others as I swipe), however, having that many within the ParentViewController
is starting to cause some crashes due to memory.
The ChildViewController
has a lot going on in it, and I'm going through it to make sure it's as efficient as possible, however, I have concerns about this approach working on older devices (as is, I'm getting crashes on the 5S).
It seems that it would help to change the view controllers to just be views, but it'd be a pretty large endeavor as the VC is complex. One suggestion I had was to create a view from the existing view controller's view, and set several delegate methods on the view and interact with the views from the ParentViewController
that way. Does any one have any thoughts on the efficiency of that method as a opposed to the current method of using ChildViewControllers
?
Another thought I had was to build a custom ContainerViewController
and have all the children in there to swipe through, but I wasn't sure if that would give me an advantage over using the children in a UIScrollView
.
Any thoughts?
I personally would not advocate the refactoring of your code to use views rather than view controllers. The view controller, itself, is unlikely to be the source of the memory problems, but rather the model objects they keep track of (as well as the assets the view controller's view uses). I think the key is to simply remove the view controllers (and their views) as they scroll off of the screen.
In your scrolling logic, as you're adding child view controllers that scroll into view, you are presumably doing all of the appropriate containment calls:
UIViewController *newChildViewController = ...
[self addChildViewController:newChildViewController];
newChildViewController.view.frame = ...;
[self.scrollView addSubview:newChildViewController.view];
[newChildViewController didMoveToParentViewController:self];
(See WWDC 2011 video Implementing UIViewController Containment for a discussion about why it's important to do these containment calls, namely to keep your view controller hierarchy synchronized with your view hierarchy.)
As the child views scroll out of view, you just do the appropriate containment calls to remove the child controller (and its view):
[childViewControllerToRemove willMoveToParentViewController:nil];
[childViewControllerToRemove.view removeFromSuperview];
[childViewControllerToRemove removeFromParentViewController];
// also remove any other strong references you have to that childViewControllerToRemove
Alternatively, you might want to contemplate using a UIPageViewController
which (in iOS 6+) offers scrolling page view (UIPageViewControllerTransitionStyleScroll
) for the transitionStyle
. This simplifies the amount of custom container code you have to write to handle the view controllers that scroll in and out of view. The UIPageViewController
is designed precisely for this situation of scrolling (or paging) through a bunch of different view controllers' views. See the Page View Controllers discussion in the View Controller Catalog for iOS.