2009-07-28 16 views
6

Ho un UITabBarController creato in modo programmatico che gestisce 4 sottoclassi di UIViewController. Qualcosa di simile:Come rendere UITabBarController carica pigramente i controller di visualizzazione?

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

C'è un modo per dire al UITabBarController per caricare i controller di vista pigramente? ej, quando l'utente fa clic su uno degli elementi della barra delle schede o quando viene chiamato tabBarController setSelectedIndex?

risposta

12

Sto facendo proprio questo in una delle mie app. Il trucco è rendere il controller di visualizzazione NON una sottoclasse di UITabBarController, ma piuttosto UIViewController e implementare UITabBarDelegate. Ho creato la vista per questo in IB, disponendo la barra delle schede (con il numero corretto di pulsanti, immagini, tag, ecc.) E un segnaposto UIView che viene utilizzato per posizionare correttamente i sottoview che sono scambiati dentro e fuori. Vedi commutazione avviene su TabBar: didSelectItem: Sembra qualcosa di simile:

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

Il codice potrebbe sicuramente essere fatto più asciutto, ma si ottiene l'idea.

+0

Ho avuto lo stesso problema dell'OP e questo codice ha funzionato perfettamente per me. Grazie!! Sono stato in grado di ridurre il tempo di avvio della mia app di 2 secondi interi. –

+0

In realtà, sto facendo ancora un po 'di lavoro e test con questo e ho avuto un problema. Se presento un controller di visualizzazione modale e poi la congedo da quella modale, quando torno al Tab Controller la sua interfaccia è tutta incasinata. Il mio UITabBar è stato spostato, l'UIView che è la sottoview del controller personalizzato della barra delle schede è stato allungato per riempire una parte maggiore dello schermo. Hai incontrato problemi come questo e se sì, hai trovato una soluzione? –

+0

@Kenny Wyland, non ho avuto problemi di questo tipo, ma non penso di aver mai provato a mostrare una vista modale su di esso. Non riesco a pensare a nessuna ragione per la testa che comunque si comporterebbe male. – zpasternack

2

Un UITabBarController richiede che i controller di visualizzazione effettivi siano impostati per la relativa proprietà viewControllers - non è disponibile il caricamento lazy dai framework Apple. Il controller della barra delle schede si basa su alcuni aspetti dei controller che carica per le sue proprietà. Tuttavia, non chiama viewDidLoad fino a quando la scheda viene premuta per la prima volta.

Ciò che si può fare è creare il proprio controller di visualizzazione "segnaposto" che, nei suoi metodi viewDidLoad o viewWillAppear, si sostituisce nel controller della barra delle schede con il proprio controller di visualizzazione effettivo. In questo modo, è possibile ridurre a icona la memoria utilizzata dai controller di visualizzazione tenuti dal controller della barra di schede fino a quando non si carica il controller di una determinata scheda e lo si sostituisce con il controller con maggiore memoria e processore.

Nota a margine: Ti consigliamo di modificare la proprietà viewControllers del controller barra delle schede direttamente, piuttosto che utilizzare il metodo setViewControllers:animated:, in modo che gli utenti non vedono l'animazione ogni volta che si carica un nuovo controller.

0

si può sempre non usare un UITabBarController e gestire l'urself barra delle linguette, quando qualcuno seleziona una scheda u spingere i viewcontrollers View in nel metodo didSelectIndex

4

Che cosa stai cercando di caricare pigramente?

Questa è un'implementazione UITabBarController piuttosto standard. Ne ho uno molto simile ad esso in un'applicazione che sto scrivendo. Nel mio codice viewDidLoad (il metodo chiamato dopo che un controller ha caricato le sue viste associate in memoria) non viene chiamato fino a quando la scheda viene toccata.

Credo che il modo in cui è stato codificato (a parte tutti gli oggetti autoreleased) sia il metodo preferito per creare questo tipo di interfaccia utente.

+0

sta rilasciando preferito autoreleasing? perché? –

+0

Il rilascio di un oggetto libera la memoria immediatamente, mentre un oggetto autoreleased deve attendere il drenaggio del pool. Su un computer desktop questo potrebbe non essere un problema, ma nel mondo della memoria iPhone è un prodotto limitato. Uno dei video di WWDC '09 sulla gestione della memoria consiglia in modo specifico l'uso dell'autelease in situazioni come questa in cui non vi è altra ragione che la stenografia del codice. – Lounges

+0

@Lounges sono nuovo nello sviluppo di iOS ... puoi spiegarmi come funziona questo controller di tabulazione? come e quando carica le sue visualizzazioni in memoria e per quanto tempo rimane in memoria –

0

All'interno del metodo didSelectItem personalizzato di UITabBarController, si dovrebbe semplicemente fare questa chiamata:

[self setSelectedViewController :[self.viewControllers objectAtIndex:0]]; 
Problemi correlati