How to make UITabBarController load view controlle

2020-05-24 19:33发布

I have a UITabBarController created programaticaly that manages 4 subclasses of UIViewController. Something like:

//Create Controller 1
    self.terminal = [[[TerminalController alloc] initWithNibName:@"TerminalView" bundle:nil] autorelease];
    UINavigationController* navTerminal = [[[UINavigationController alloc] initWithRootViewController:terminal] autorelease];
    navTerminal.title = __(@"Terminal");
    navTerminal.navigationBar.barStyle = UIBarStyleBlackOpaque;
    navTerminal.tabBarItem.image = [UIImage imageNamed:@"tab_terminal.png"];        

    //Create Controller 2
    self.history = [[[HistoryController alloc] initWithNibName:@"HistoryView" bundle:nil] autorelease];
    UINavigationController* navHistory =  [[[UINavigationController alloc] initWithRootViewController:history] autorelease];
    navHistory.title = __(@"History");
    navHistory.navigationBar.barStyle = UIBarStyleBlackOpaque;
    navHistory.tabBarItem.image = [UIImage imageNamed:@"tab_history.png"];

    //Create Controller 3
    self.settings = [[[SettingsController alloc] initWithNibName:@"SettingsView" bundle:nil] autorelease];
    UINavigationController* navSettings =  [[[UINavigationController alloc] initWithRootViewController:settings] autorelease];
    navSettings.title = __(@"Settings");
    navSettings.navigationBar.barStyle = UIBarStyleBlackOpaque;
    navSettings.tabBarItem.image = [UIImage imageNamed:@"tab_settings.png"];

    //Create Controller 4
    HelpController* help = [[[HelpController alloc] initWithNibName:@"HelpView" bundle:nil] autorelease];
    UINavigationController* navHelp =  [[[UINavigationController alloc] initWithRootViewController:help] autorelease];
    navHelp.title = __(@"Help");
    navHelp.navigationBar.barStyle = UIBarStyleBlackOpaque;
    navHelp.tabBarItem.image = [UIImage imageNamed:@"tab_help.png"];

    //Create Tab Bar an add it's view to window.
    self.tabBar = [[[UITabBarController alloc] initWithNibName:nil bundle:nil] autorelease];
    tabBar.viewControllers = [[[NSArray alloc] initWithObjects:navTerminal, navHistory, navSettings, navHelp, nil] autorelease];
    tabBar.delegate = self;     

    [window addSubview:tabBar.view];

Is there a way to tell the UITabBarController to load the view controllers lazily? ej, when the user clicks one of the tab bar items or when tabBarController setSelectedIndex is called?

标签: iphone
5条回答
贪生不怕死
2楼-- · 2020-05-24 20:18

I'm doing this very thing in one of my apps. The trick is to make your view controller NOT be a subclass of UITabBarController, but rather UIViewController, and implement UITabBarDelegate. I created the view for this in IB, laying out the tab bar (with the proper # of buttons, images, tags, etc.) and a placeholder UIView which is used to properly place the subviews that are swapped in and out. View switching happens on tabBar:didSelectItem: It looks something like this:

// MyTabBarController.h
@class MyFirstViewController;
@class MySecondViewController;
@class MyThirdViewController;

@interface MyTabBarController : UIViewController <UITabBarDelegate> {
    IBOutlet UIView *placeholderView;
    IBOutlet UITabBar *tabBar;
    MyFirstViewController *firstViewController;
    MySecondViewController *secondViewController;
    MyThirdViewController *thirdViewController;
    UIViewController *currentViewController;
}
@property (nonatomic, retain) MyFirstViewController *firstViewController;
@property (nonatomic, retain) MySecondViewController *secondViewController;
@property (nonatomic, retain) MyThirdViewController *thirdViewController;

- (void) switchToView:(UIViewController*)aViewController;
@end


//  MyTabBarController.m
#import "MyTabBarController.h"
#import "MyFirstViewController.h"
#import "MySecondViewController.h"
#import "MyThirdViewController.h"

enum {
    kView_First = 1,
    kView_Second,
    kView_Third
};

@implementation MyTabBarController

@synthesize firstViewController, secondViewController, thirdViewController;

- (void) viewDidLoad {
    // Default to first view.
    tabBar.selectedItem = [tabBar.items objectAtIndex:0];
    MyFirstViewController *viewController = [[MyFirstViewController alloc] initWithNibName:@"FirstView" bundle:nil];
    self.firstViewController = viewController;
    [viewController release];
    [self switchToView:firstViewController];
}

- (void)viewWillAppear:(BOOL)animated {
    // Tell our subview.
    if( currentViewController != nil ) {
        [currentViewController viewWillAppear:animated];
    }
}

- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item {
    switch (item.tag) {
        case kView_First: {
            if (firstViewController == nil) {
                MyFirstViewController *viewController = [[MyFirstViewController alloc]
                    initWithNibName:@"FirstView" bundle:nil];
                self.firstViewController = viewController;
                [viewController release];
            }

            [self switchToView:firstViewController];
        }
        break;

        case kView_Second:
            if (secondViewController == nil) {
                MySecondViewController *viewController = [[MySecondViewController alloc]
                initWithNibName:@"SecondView" bundle:nil];
                self.secondViewController = viewController;
                [viewController release];
            }

            [self switchToView:secondViewController];
            break;

        case kView_Third: {
            if (timesViewController == nil) {
                MyThirdViewController *viewController = [[MyThirdViewController alloc]
                initWithNibName:@"ThirdView" bundle:nil];
                self.thirdViewController = viewController;
                [viewController release];
            }

            [self switchToView:thirdViewController];
        }
        break;              
    }
}

- (void) switchToView:(UIViewController*)aViewController {
    if( aViewController == currentViewController ) return;

    UIView *aView= aViewController.view;                
    [aViewController viewWillAppear:NO];
    if( currentViewController != nil ) {
        [currentViewController viewWillDisappear:NO];
        [currentViewController.view removeFromSuperview];       
    }
    aView.frame = placeholderView.frame;
    [self.view insertSubview:aView aboveSubview:placeholderView];
    if( currentViewController != nil ) {
        [currentViewController viewDidDisappear:NO];
    }
    [aViewController viewDidAppear:NO];
    currentViewController = aViewController;
}
@end

The code could surely be made more DRY, but you get the idea.

查看更多
迷人小祖宗
3楼-- · 2020-05-24 20:25

What are you trying to load lazily?

This is a pretty standard UITabBarController implementation. I have one very similar to it in an application I am writing. In my code the viewDidLoad (the method called after a controller has loaded its associated views into memory) is not called until the tab is touched.

I do believe the way you have coded (aside from all of the autoreleased objects) is the preferred method of creating this kind of UI.

查看更多
时光不老,我们不散
4楼-- · 2020-05-24 20:34

A UITabBarController requires that actual view controllers be set for its viewControllers property - there's no lazy loading available from Apple's frameworks. The tab bar controller relies on certain aspects of the controllers it loads for its properties. However, it doesn't call viewDidLoad until the tab is pressed for the first time.

What you can do instead is create your own "placeholder" view controller that, in its viewDidLoad or viewWillAppear methods, replaces itself in the tab bar controller with its actual view controller. That way, you can minimize the memory used by the view controllers held by the tab bar controller until you load a certain tab's view controller and replace it with your more memory- and processor-intensive controller.

Side note: You'll want to change the tab bar controller's viewControllers property directly, rather than use the setViewControllers:animated: method, so that your users don't see an animation every time you load a new controller.

查看更多
何必那么认真
5楼-- · 2020-05-24 20:37

You can always not use a UITabBarController and manage the tabbar urself, when someone selects a tab u push the viewcontrollers view in in the didSelectIndex method

查看更多
男人必须洒脱
6楼-- · 2020-05-24 20:38

Within the custom UITabBarController's didSelectItem method, you should simply just make this call:

[self setSelectedViewController :[self.viewControllers objectAtIndex:0]];
查看更多
登录 后发表回答