How to optimize performance in view controller navigation with UISegmentedControl and UITabBarController
On a project I'm working on, the design decision was to use a UISegmentControl at the top, with a UITabBarController on the bottom. The UISegmentControl has 3 choices for 3 different views. Currently, my coworker has added all 3 views to an NSArray when that particular tab is selected, and then based on the UISegmentControl, the view selected gets unhidden, and the other two are hidden. It seems to not follow Apple's guidelines of lazy loading and seems expensive since 3 viewDidLoads (where queries are made to a database) are getting all loaded at once. There is some lag because of it when the tab is selected for the first time, loading all 3 viewControllers at once. 开发者_高级运维
Is there a better way to do this? I saw a simple example with just two viewControllers, and a button that would switch between the two views. That makes sense to me since you always know what your previous view was, and you can remove that view from the superview, present your new one, release your old one. But with 3 choices, I do not know how to keep track of my view hierarchy (since I could be on segment 0, showing view 0, and then go to segment 2, showing view 2). I am not sure how to check for the last view that was shown, and even if that's the best method. I'm thinking that if there is a better option to keep track of this, but still using the segment control, might as well do it now before the project gets more complex. Thanks!
I would suggest creating a root view controller whose job it is to manage the segment control and load the proper VC depending on which button in the segmented control is selected. The root VC's view would have a subView where the segmented control's VC views are inserted. Something like:
- (void)segmentAction:(id)sender
{
NSParameterAssert([sender isKindOfClass: [UISegmentedControl class]]);
switch ([sender selectedSegmentIndex]) {
case 0:
MYViewController1 *vc = [[MyViewController1 alloc] init];
self.segmentVC = vc;
self.segmentSubvew = vc.view;
[vc release];
break;
}
}
One thing people tend to get hung up on is that there needs to be only 1 VC per screenfull of content -- while that was originally what was recommended by Apple, they have since changed this recommendation. So, loading your segment specific VCs inside the SegmentManagerVC is perfectly acceptable.
You could further tweak this design for performance. For example, you could initially load the VC for the default selected segment and then lazy load the other two so they are already available when a different segment is selected. If you take this approach, though, be sure to hook up -didReceiveMemoryWarning
to release the two VCs that aren't currently being viewed.
You could push/pop views onto the UINavigationControler stack. This would also support a "back" button if you wanted it.
[self.navigationController pushViewController:self.myVC animated:YES];
Link a method up to the SegmentedControl that pushes the appropriate ViewController when the corresponding segment is selected. The VC with your segmented control inside of it would need a reference to each segment's corresponding VC. viewDidLoad()
will only be called once, and only when the view is pushed onto the navigation stack for the first time.
When you change views or want to go "back", you can pop the VC off the stack:
[self.navigationController popViewControllerAnimated:YES];
Is this the type of functionality which you were looking for?
Edit for Clarity
UIViewController References:
Each view will need a reference to the other two view's ViewControllers. This can be done like this: (assume that we are in "View1", and we also have "View2" and "View3":
View2Controller v2Controller = [[View2Controller alloc] initWithNibName:@"View2" bundle:nil];
View3Controller v2Controller = [[View3Controller alloc] initWithNibName:@"View3" bundle:nil];
The reference to self.navigationController
should be declared in your app's delegate as:
UINavigationController* navigationController;
It can be initialized as:
[navigationController initWithRootViewController: rootViewController];
The RootViewController
rootViewController
is the UIViewController that corresponds to your application's root view (whatever loads on startup). It is declared in the delegate as:
RootViewController* rootViewController;
And initialized as:
rootViewController = [[RootViewController alloc] initWithNibName:@"RootViewController" bundle:nil];
精彩评论