2009-07-28 4 views
6

Tengo un UITabBarController creado programáticamente que gestiona 4 subclases de UIViewController. Algo así como:¿Cómo hacer que UITabBarController cargue los controladores de vista de forma perezosa?

//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]; 

¿Hay una manera de contar la UITabBarController para cargar los controladores de vista con pereza? ej, cuando el usuario hace clic en uno de los elementos de la barra de pestañas o cuando se llama a tabBarController setSelectedIndex?

Respuesta

12

Estoy haciendo esto mismo en una de mis aplicaciones. El truco es hacer que su controlador de vista NO sea una subclase de UITabBarController, sino más bien UIViewController, e implementar UITabBarDelegate. Creé la vista para esto en IB, tendiendo la barra de pestañas (con el número correcto de botones, imágenes, etiquetas, etc.) y un marcador de posición UIView que se utiliza para colocar correctamente las subvistas que se intercambian dentro y fuera. Ver conmutación ocurre en la barra de pestañas: didSelectItem: Se ve algo como esto:

// 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 

El código de seguridad se podrían hacer más seco, pero se entiende la idea.

+0

Tuve el mismo problema que el OP y este código funcionó perfectamente para mí. ¡¡Gracias!! Pude reducir el tiempo de inicio de mi aplicación en 2 segundos completos. –

+0

En realidad, estoy haciendo un poco más de trabajo y pruebas con esto y me encontré con un problema. Si presento un Controlador de Vista Modal y luego desestimo ese modal, cuando regrese al Controlador de Pestaña su interfaz está completamente estropeada. Mi UITabBar se ha movido, la UIView que es la subvista del controlador de la barra de pestañas personalizada se ha extendido para ocupar más de la pantalla. ¿Te has encontrado con problemas como este y, de ser así, has encontrado una solución? –

+0

@Kenny Wyland, no he tenido ningún problema como este, pero no creo que haya intentado mostrar una vista modal sobre él. No puedo pensar en ninguna razón fuera de mi cabeza que se portaría mal así, sin embargo. – zpasternack

2

Un UITabBarController requiere que los controladores de vista reales se establezcan para su propiedad viewControllers; no hay carga diferida disponible en los marcos de trabajo de Apple. El controlador de la barra de pestañas depende de ciertos aspectos de los controladores que carga para sus propiedades. Sin embargo, no llama al viewDidLoad hasta que se presione la pestaña por primera vez.

Lo que puede hacer en su lugar es crear su propio controlador de vista "marcador de posición" que, en sus métodos viewDidLoad o viewWillAppear, se reemplaza en el controlador de la barra de pestañas con su controlador de vista real. De esta forma, puede minimizar la memoria utilizada por los controladores de vista mantenidos por el controlador de la barra de pestañas hasta que cargue el controlador de vista de cierta pestaña y lo reemplace con su controlador más intensivo de memoria y procesador.

Nota al margen: querrá cambiar directamente la propiedad viewControllers del controlador de la barra de pestañas, en lugar de usar el método setViewControllers:animated:, para que sus usuarios no vean una animación cada vez que cargue un nuevo controlador.

0

Siempre no se puede utilizar un UITabBarController y gestionar el Urself barra de pestañas, cuando alguien selecciona una pestaña u empujar el viewcontrollers ver en en el método didSelectIndex

4

¿Qué está tratando de cargar con pereza?

Esta es una implementación UITabBarController bastante estándar. Tengo uno muy similar en una aplicación que estoy escribiendo. En mi código, el viewDidLoad (el método llamado después de que un controlador haya cargado sus vistas asociadas en la memoria) no se llama hasta que se toca la pestaña.

Creo que la forma en que ha codificado (aparte de todos los objetos liberados automáticamente) es el método preferido para crear este tipo de interfaz de usuario.

+0

es la liberación preferido autoreleasing? ¿porqué es eso? –

+0

La liberación de un objeto libera la memoria de inmediato, mientras que un objeto liberado automáticamente tiene que esperar a que se drene la agrupación. En una computadora de escritorio esto puede no ser un problema, pero en el mundo de la memoria del iPhone es un producto limitado. Uno de los videos de la WWDC '09 sobre gestión de memoria recomienda específicamente no utilizar el autorrelease en situaciones como esta, donde no hay otra razón que no sea el código abreviado. – Lounges

+0

@Lounges Soy nuevo en el desarrollo de iOS ... ¿me puede explicar cómo funciona este controlador de pestañas? cómo y cuándo carga sus vistas en la memoria y cuánto tiempo permanece en la memoria –

0

Dentro del método de didSelectItem UITabBarController personalizada, debería simplemente hacer esta llamada:

[self setSelectedViewController :[self.viewControllers objectAtIndex:0]]; 
Cuestiones relacionadas