mk12
mk12

Reputation: 26364

iPhone Dev - Lazy loading a Tab Bar app

How can I make it so when a tab is selected, the current one is unloaded, and the next one is loaded so only one loaded at a time? Or should I not even do this? I know how to do it with a normal UIViewController as the root VC, but not sure with a UITabBarController. Also, is there a way to animate the transition from one tab to the next? Any help? Thanks!!

EDIT: ... If I unload the view controllers, then their icons on the tab bar are gone... maybe I'll just unload their views..

Upvotes: 0

Views: 5753

Answers (6)

Andy
Andy

Reputation: 4746

I'm currently using this to unload inactive view controllers in the tab bar (based on Kendall's answer)

- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:  (UIViewController *)viewController {
    // reload all inactive view controllers in the tab bar
 for (UIViewController *vc in tabBarController.viewControllers) {
  if(vc != viewController)
   [vc didReceiveMemoryWarning];

} }

Upvotes: -1

valvoline
valvoline

Reputation: 8117

Lazy loading is not an UITabBarController task. Instead, it is responsability of your viewControllers associated with your Tab.

To release the UIView, associated with each UIViewControllers, every time you change the TabBarItem, you must implement the following method in each UIViewController subclass, associated with your UITabBarController.viewControllers property:

-(void)viewDidDisappear {
[self.view removeFromSuperview];
self.view = nil;
}

Obviously, this will remove the self.view associated with your UIViewController. However, if your code is smart enough, this will remove all the related objects. For example, suppose that your loadView method is as follow:

-(void)loadView {
UIView *contentVew = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.view = contentView;
…
...
UILabel *aLabel = [[UILabel alloc] initWithFrame:CGRectMake(0,0,320,50)];
…
…
[contentView addSubview:aLabel];
[aLabel release];
…

[contentView release];
}

This means that every object inside the contentView and their memory responsabilities are demanded to the contentView, that is released and attached to the self.view property.

In this scenario, removing the self.view (that's the reference to the contentView) resulting in a domino-style releasing of every object, that's your goal.

Best regards

Upvotes: 1

adonoho
adonoho

Reputation: 4339

UITabBarController does lazy load all of its view controllers. When a tab is switched out, then it's view is subject to being deallocated in a memory tight situation. It is then recreated when it is chosen the second time. Furthermore, most of your memory hits are in your views and not the view controllers. Hence, don't worry about the memory hit from the view controller. The view is the proze.

If you are running on v3 of the OS, then you can use the -viewDidUnload method to ensure the maximal amount of memory reduction.

Andrew

Upvotes: -1

Daniel
Daniel

Reputation: 22395

You cant really manage the UITabBarController unfortunaly so you cant do lazy loading. You can by managining your own TabBar but you said u knew that already,

to manage your own tab bar though all you gotta do is setup a UITabBar with its TabBarItems in a ViewController, then implement the TabBar Delegate protocol, mainly the – tabBar:didSelectItem: method which is called whenever the tabbarItem selection is changed, then based on the item id you can load your new ViewController and release any others so: Edit: this code goes in your UIViewController

  -(void)addTabBar{
    NSMutableArray* items=[[NSMutableArray alloc] init];
    UITabBarItem *eventsItem= [[UITabBarItem alloc] initWithTitle:@"Events" image:nil   tag:0];
    UITabBarItem *albumItems=[[UITabBarItem alloc] initWithTitle:@"Album" image:nil tag:1]; //the tag is how you tell what was clicked
    [items addObject:homeItem];
    [items addObject:albumItems];
      //MyTabBar is of type UITabBar
    myTabBar=[[UITabBar alloc] initWithFrame:CGRectMake(0,411,320,49)];
    [myTabBar setItems:items];
    myTabBar.delegate=self; //you gotta implement the UITabBar delegate protocol
    [myTabBar setSelectedItem:eventItem]; //set the selected item
    [homeItem release];
    [eventsItem release];
    [albumItems release];
    [items release];
   [self.view addSubview:myTabBar]
}

then the protocol method would look something like below - (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item { if(item.tag == 0 ) { //load the ViewController that pertains to this item and release others } ...etc

}

Upvotes: 1

I can answer both questions in one...

You just need a class that acts as the UITabBarController delegate, then implement a method like so:

// Animate tab selections so they fade in and fade out
-(void)tabBarController:(UITabBarController*)tbc didSelectViewController:(UIViewController*)newSelection
{
    [UIView beginAnimations:@"TabFadeIn" context:nil];
    [UIView setAnimationDuration:0.6];
    for( UIViewController* vc in tbc.viewControllers )
        vc.view.alpha = (vc==newSelection) ? 1 : 0;
    [UIView commitAnimations];  
}

Now my code simply makes the tab bars fade in and out, but you could also do work here to unload non-used tabs. Sometimes that is a good idea if some of the tabs will be using a ton of memory.

Upvotes: 3

Jordan
Jordan

Reputation: 21760

Not sure why you'd want to do this, the current tab will get unloaded anyway if there's a memory issue involved. That's what -viewWillAppear, -viewDidUnload, etc. are for.

Upvotes: -1

Related Questions