Lo scopo di questa guida è riuscire a scrivere un’applicazione basata sull’utilizzo di una TabBar che gestisca differenti tipologie di view controller, ovvero da una semplice UIViewController fino ad arrivare ad una basilare implementazione di UINavigationController e relative view associate. La guida si prepone inoltre di effettuare tutte le operazioni necessarie via codice, senza mettere mano in nessun caso ad Interface Builder.

Il nostro progetto
Iniziamo col creare un nuovo progetto, di tipo Window-Based application e diamogli il nome che preferiamo: io ho scelto “TutorialTabBar”. Fatto ciò, apriamo la cartella Classes: saranno presenti i file di header ed implementazione della classe che fa da delegato di UIApplication; non entriamo troppo nei dettagli, ma è qui che viene scritto il codice per caricare l’interfaccia iniziale della nostra applicazione.
La prima cosa da fare è dichiarare il nostro UITabBarController e siccome esso sarà presente sempre nella nostra applicazione, converrà dichiararlo nel file di header, infatti:
#import
@interface TutorialTabBarAppDelegate : NSObject {
UIWindow *window;
UITabBarController *tabBarController;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) UITabBarController *tabBarController;
@end
Si noti come lʼoggetto di tipo UITabBarController non è un IBOutlet (come la variabile di tipo UIWindow, l’unica gestita tramite Interface Builder).
Andiamo nel file di implementazione, individuiamo il metodo “application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary *)launchOptions” e scriviamo lì il codice che servirà a caricare appunto l’interfaccia della nostra applicazione.
Ci servirà un oggetto di tipo NSMutableArray in cui raccoglieremo mano a mano i diversi controller per i diversi Tab; allochiamo ed inizializziamo l’oggetto di tipo UITabBarController, impostiamo la sua variabile di tipo NSArray viewControllers come “controllers”, e rilasciamo appunto “controllers” (non ci serve più). Infine aggiungiamo alla window la view di UITabBarController (che sottolineo, non è altro che una sottoclasse di UIViewController); senza dimenticarsi di includere l’oggetto UITabBarController in @synthetize (è una property, quindi devo anche sintetizzarla) e di deallocarla nel metodo dealloc, otterremo un codice che somiglierà a questo:
#import "TutorialTabBarAppDelegate.h"
@implementation TutorialTabBarAppDelegate
@synthesize window,tabBarController;
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSMutableArray *controllers = [[NSMutableArray alloc] initWithCapacity:3];
tabBarController = [[UITabBarController alloc] init];
// -----------------------------------------
tabBarController.viewControllers = controllers;
[controllers release];
[window addSubview:tabBarController.view];
[self.window makeKeyAndVisible];
return YES;
}
#pragma mark -
#pragma mark Memory management
- (void)dealloc {
[tabBarController release];
[window release];
[super dealloc];
}
@end
Si noti come non ho fatto alcun cenno alla gestione della memoria, ed al perché su quellʼoggetto di nome “controllers” è stato fatto un release: non è lo scopo di questa guida, quindi invito a chi non è avvezzo a tale argomento a riguardarselo, per poter avere unʼidea più chiara sulle operazioni di retain e release. Ma voglio però dare una piccola spiegazione sul perché ho dato una capacità iniziale di 3 allʼoggetto “controllers”: il
compilatore sa che in questo array verranno inseriti almeno 3 oggetti, dunque invece di allocare tre aree di memoria differenti con un indirizzo per ognuna di esse, verrà allocata una sola zona in cui inserirli e sarà necessario un solo indirizzo per individuarli.
Ovviamente il discorso non vale se non conoscete a priori il numero degli oggetti da inserire nellʼarray.
Potete anche compilare ed eseguire: tutto funzionerà alla perfezione, ma la TabBar sarà vuota:

Aggiungiamo un UIViewController
Adesso aggiungiamo le diverse view alla TabBar. Create un nuovo file di tipo UIViewController, dategli un nome a vostro piacimento (io l’ho chiamato “Tab1ViewController”). Esso gestirà una view, che a sua volta conterrà una subview di tipo UILabel con un testo a piacimento. Quindi, nel file header dichiariamo un oggetto NSString che servirà appunto ad impostare il testo dellʼUILabel, ed aggiungiamolo come property:
#import
@interface Tab1ViewController : UIViewController {
NSString *testo;
}
@property (nonatomic, retain) NSString *testo;
@end
Nel file di implementazione invece utilizziamo il metodo loadView per caricare lʼinterfaccia di questa view: creazione della view principale (che occpuerà tutto lo schermo visibile), creazione dellʼUILabel ed il suo posizionamento nella view principale, senza dimenticare del synthetize della NSString e della sua deallocazione:
- (void)loadView {
CGRect rectViewPrincipale = CGRectMake(0.0, 0.0, 320.0, 411.0);
UIView *viewPrincipale = [[UIView alloc] initWithFrame:rectViewPrincipale];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10.0, 30.0, 300.0, 21.0)];
label.textAlignment = UITextAlignmentCenter;
label.text = testo;
[viewPrincipale addSubview:label];
[label release];
self.view = viewPrincipale;
[viewPrincipale release];
}
Torniamo al file di implementazione del nostro AppDelegate: facciamo un import del nuovo file header e scriviamo il codice che serve a crearlo e ad aggiungerlo allʼinterfaccia dellʼapp: allochiamo ed inizializziamo, diamo un titolo, impostiamo la stringa da visualizzare a nostro piacimento, aggiungiamo il nuovo view controller allʼarray controllers e poi lo rilasciamo. Compiliamo ed eseguiamo…
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSMutableArray *controllers = [[NSMutableArray alloc] initWithCapacity:2];
tabBarController = [[UITabBarController alloc] init];
// -----------------------------------------
Tab1ViewController *tab1Controller = [[Tab1ViewController alloc] initWithNibName:nil bundle:nil];
tab1Controller.title = @"Tab 1";
tab1Controller.testo = @"Testo di prova Tab 1";
[controllers addObject:tab1Controller];
[tab1Controller release];
// -----------------------------------------
tabBarController.viewControllers = controllers;
[controllers release];
[window addSubview:tabBarController.view];
[self.window makeKeyAndVisible];
return YES;
}

Aggiungiamo un UITableViewController
Creiamo un nuovo file, questa volta sarà un oggetto di tipo UITableViewController, e diamogli un nome (io ho scelto “Tab2ViewController”). Dichiariamo un nuovo oggetto nel file di implementazione, di tipo NSArray, il quale conterrà tutti gli elementi da inserire nelle celle (in questo caso saranno stringhe); nel file di implementazione allochiamo ed inizializziamo lʼarray (senza dimenticarci dei soliti synthetize e dealloc), in numberOfSectionsInTableView: ritorniamo il valore 1 (una sola sezione per la tabella), in numberOfRowsInSection: ritorniamo la dimensione dellʼarray, ed in cellForRowAtIndexPath: invece è tutto già pronto, dobbiamo solo impostare il testo della cella recuperandolo dallʼarray dei dati (non discuto sul come farlo, esula dagli scopi di questa guida lʼimplementazione di una UITableView). Quindi dovreste ottenere una cosa del genere:
- (void)viewDidLoad {
[super viewDidLoad];
vociTabella = [[NSArray alloc] initWithObjects:@"iPhone", @"iPod", @"iPod touch", @"iPad",
@"iMac", @"Mac Pro", @"iBook",
@"MacBook", @"MacBook Pro", @"PowerBook", nil];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return vociTabella.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = [vociTabella objectAtIndex:indexPath.row];
return cell;
}
Sempre nel file di implementazione di AppDelegate, eseguiamo le solite operazioni: importiamo lʼheader del nuovo UITableViewController, dichiariamo ed inizializziamo il nuovo oggetto (questa volta impostando lo stile della tabella), scegliamo un titolo, aggiungiamo il tutto allʼarray dei controllers e rilasciamo. Compiliamo ed eseguiamo:

Notate come UITableViewController si occupa in maniera del tutto automatica del posizionamento di UITableView allʼinterno dello schermo, a differenza che nel caso precedente dove eravamo noi a dover impostare le dimensioni; questo è giustificato dal fatto che in un generico UIViewController Apple da allo sviluppatore la libertà di fare ciò che vuole con la UIView che questo controller deve gestire, mentre UITableViewController deve invece gestire UITableView, e dunque le dimensioni vengono calcolate in maniera
automatica.
Aggiungiamo un UINavigationController
Proseguiamo col nostro tutorial: questa volta il terzo tab di UITabBar dovrà contenere un UINavigationController che ci permetterà di passare da una view allʼaltra in maniera del tutto automatica. Per prima cosa, creiamo un nuovo UITableViewController ed eseguiamo esattamente tutte le operazioni effettuate precedentemente (ma proprio tutte!), in più aggiungiamo un Disclosure Indicator alle celle della tabella, per indicare allʼutente che è possibile toccarle e visualizzare ulteriori dettagli per quella voce. Utilizzeremo il view
controller che abbiamo creato prima, ma con una piccola modifica: il view controller deve sapere se la sua view è inserita in un UINavigationController o meno, per regolarne le dimensioni: quindi modifichiamo i nostri file aggiungendo una variabile di tipo BOOL che indica appunto se questa opzione si verifica o meno, ed implementiamo il tutto nel file .m:
#import
@interface Tab1ViewController : UIViewController {
NSString *testo;
BOOL viewInNavigation;
}
@property (nonatomic, retain) NSString *testo;
@property (nonatomic) BOOL viewInNavigation;
@end
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
viewInNavigation = NO;
}
return self;
}
- (void)loadView {
CGFloat heightView = viewInNavigation ? 367.0 : 411.0;
CGRect rectViewPrincipale = CGRectMake(0.0, 0.0, 320.0, heightView);
// Tutto uguale a prima...
}
Si noti come sia stato sovrascritto il metodo init del view controller: lʼabbiamo fatto perché la variabile deve avere per forza di cose un valore, che sia YES o NO; io ho scelto questʼultimo valore come default.
Andiamo in AppDelegate, importiamo lʼheader del nuovo UITableViewController, dichiariamo ed inizializziamo il nuovo oggetto (impostando lo stile della tabella) e scegliamo un titolo; adesso dichiariamo ed inizializziamo con il Tab3ViewController un nuovo oggetto, di tipo UINavigationController (sottoclasse di UIViewController), che si occuperà del passaggio tra una view e lʼaltra, ed includiamolo nellʼarray controllers:
Tab3ViewController *tab3Controller = [[Tab3ViewController alloc] initWithStyle:UITableViewStylePlain];
tab3Controller.title = @"Tab 3";
UINavigationController *nav3Controller = [[UINavigationController alloc] initWithRootViewController:tab3Controller];
[controllers addObject:nav3Controller];
[nav3Controller release];
[tab3Controller release];
Torniamo a didSelectRowAtIndexPath: e scriviamo il codice che ci serve per importare il view controller (il suo file header), allocarlo ed inizializzarlo, dirgli che siamo in presenza di un UINavigationController, impostare titolo e testo, ed eseguire lʼoperazione di push sul suo navigation controller… che significa questʼultima cosa? È presto detto: lʼistruzione self.navigationController richiama appunto lʼoggetto UINavigationController di cui
Tab3ViewController fa parte: siccome è questʼultimo controller ad essere visualizzato in primo piano in quel momento, dobbiamo dire ad UINavigationController che vi deve sostituire lʼoggetto di tipo Tab1ViewController appena creato, eseguendo appunto unʼoperazione di push. Fatto questo, lo rilasciamo:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *voce = [vociTabella objectAtIndex:indexPath.row];
Tab1ViewController *viewController = [[Tab1ViewController alloc] initWithNibName:nil bundle:nil];
viewController.viewInNavigation = YES;
viewController.title = voce;
viewController.testo = voce;
[self.navigationController pushViewController:viewController animated:YES];
[viewController release];
}
Compiliamo ed eseguiamo…

La tabella che viene visualizzata nel terzo tab è sensibile al tocco dellʼutente: una volta toccata una cella, verrà visualizzato un UIViewController, che prenderà il posto della tabella iniziale tramite unʼanimazione di scorrimento: di sostituzione ed animazione si occupa appunto UINavigationController, il quale è anche responsabile della creazione del pulsante in alto a sinistra nella UINavigationBar (la barra di colore blu al in alto) utilizzato per eseguire lʼoperazione cosiddetta di pop, e tornare alla tabella iniziale.
Se avete problemi con il tutorial, questo è il nostro file di progetto.












30 Responses to “T#084 – Differenti tipi di View Controller per le nostre TabBar”
14 Febbraio 2011
Tweets that mention Differenti tipi di View Controller per le nostre TabBar | devAPP -- Topsy.com[…] This post was mentioned on Twitter by Rynox and iPadWorld.it, devAPP. devAPP said: T#084 – Differenti tipi di View Controller per le nostre TabBar http://bit.ly/gtEuab […]
14 Febbraio 2011
danielaFantastico !
Ci provo subito
14 Febbraio 2011
FrancescoPersonalmente preferisco scrivere meno codice possibile e usare Interface Builder, la guida è scritta bene comunque!
15 Febbraio 2011
MatFur92Bella guida!!
Comunque avrei una domanda a riguardo…io per creare la tabella ho utilizzato come classe la UIViewController per riuscir anche a posizionare anche altri elementi nella vista, tutto perfetto fino al momento di utilizzare il metodo reloadData che non è implementato in questa superclasse ma soltanto nella sottoclasse UITableViewController.
Quache idea sul come risolvere il problema?
15 Febbraio 2011
FrancescoChiama il metodo reloadData sulla tableView
15 Febbraio 2011
Pasquale MatriscianoQuando hai UITableViewController cosa fai per richiamare il metodo reloadData? Così:
[self.tableView reloadData];
Nel tuo caso dei fare la stessa cosa, ovvero come ti è stato detto da Francesco richiamare il metodo su UITableView; certamente sarà una variabile d’istanza della tua classe, dunque accessibile in ogni metodo e se poi è anche una property la forma è identica alla precedente:
[self.tuaTabella reloadData];
15 Febbraio 2011
MatFur92Capito! Grazie mille!! 😉 Appena torno a casa provo!!! =D
GRAZIE ANCORA Francesco e Pasquale!!
17 Febbraio 2011
barochCiao! Grazie per questi meravigliosi tutorial sono perfetti! Io però mi trovo davanti ad un problema enorme che non riesco a risolvere in nessun modo: Se volessi integrare nella terza view una barra di search come posso fare? Non ce la faccio in nessun modo da codice (mi sento anche un po’ impedita) e non c’è il file di xib per farlo da Interface Builder (cosa che non mi dispiace perchè non mi piace fare le cose da Interface Builder). Spero mi rispondiate presto! Grazie ancora mi state salvando la vita!
17 Febbraio 2011
Pasquale MatriscianoCiao a te. È molto semplice fare ciò che chiedi: in generale, devi sempre immaginare che non c’è più IB che alloca ed inizializza gli oggetti per te, ma sei tu a doverlo fare; se da una parte ci perdi in praticità, dall’altra ci guadagni in comprensione ed elasticità. Ma veniamo a noi: nel metodo -(void)loadView non devi far altro che crearti la tua UISearchBar, impostarne i parametri a tuo piacimento ed utilizzarla per creare il UISearchViewController. Ad esempio puoi fare in questo modo:
// Allochi ed inizializzi la UISearchBar
UISearchBar *searchBar = [[UISearchBar alloc] init];
// Ne adatti le dimensioni alla larghezza dello schermo
[searchBar sizeToFit];
// Imposti un testo iniziale (che apparirà in grigio) – opzionale!!
searchBar.placeholder = NSLocalizedString(@”Cerca un qualcosa”,@””);
// La posizioni nella tua tabella
self.tableView.tableHeaderView = searchBar;
// Allochi ed inizializzi il UISearchDisplayController con la UISearchBar appena creata
UISearchDisplayController *searchController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
// Delegato, data source dei risultati e delegato dei risultati saranno la tua UITableViewController
searchController.delegate = self;
searchController.searchResultsDataSource = self;
searchController.searchResultsDelegate = self;
// Rilasci la UISearchBar
[searchBar release];
Per il resto è tutto uguale a come fai con IB… spero ti sia tutto chiaro, in caso contrario scrivi pure!
20 Febbraio 2011
buzzociao, molto bello il tutorial ma è tutto scritto e sinceramente ci capisco poco (anche perchè sono alle prime armi con l’objective-c) e volevo chiedrti se potevi ripropporre lo stesso tutorial usando però anche l’interface builder, grazie
21 Febbraio 2011
Pasquale MatriscianoCiao, se vuoi ti accontento: posso scriverlo utilizzando IB ed il meno possibile il codice, anche se lo scopo del tutorial era quello di far comprendere come opera davvero Cocoa attraverso Objective-C e come sia possibile fare tutto ciò che si desidera senza limitarsi ad una interfaccia grafica. In ogni caso, mi rendo conto che IB è uno strumento molto utilizzato, quindi potrei scriverlo non ci sono problemi; vorrei solo invitarti a rileggere il testo prima di abbandonarti a IB, e magari fare qualche domanda su punti che non ti sono molto chiari: ne guadagnerai in elasticità 🙂
21 Febbraio 2011
barochGrandissimo grazie! Finalmente ho la mia search e senza usare IB che proprio non mi piace!!!!! Una cosa che non c’entra un granchè con questo tutorial ma mi verrebbe molto utile… non è che mi fate un tutorial sull’in app purchase? Perchè tutto ciò che c’è in giro è in inglese e molto confuso e visto che mi sembra un’operazione molto complessa che tra l’altro non si può testare sul simulatore (e vorrei evitare di salutare il mio iphone per errori di sviluppo) mi sarebbe molto utile! Grazie mille in ogni caso – Chiara
25 Febbraio 2011
GamvaDmitici!
Come faccio a visualizzare del testo scorrevole differente per ogni view-dettagli richiamata dalla tabella??
grazie
28 Febbraio 2011
Pasquale MatriscianoDevi utilizzare la classe UITextView ed impostarne il testo (ad esempio) attraverso il sistema che io ho utilizzato per impostarlo su UILabel.
3 Marzo 2011
GamvaDGrazie per la risposta!
Si può fare qualcosa simile alle celle personalizzate?
UILabel *titolo = (UILabel *)[cell viewWithTag:1];
titolo.text = [lista objectAtIndex:indexPath.row];
Stavo provando con:
UITextView *scroll = (UITextView *)[ ?? viewWithTag:1];
scroll.text = [ ??? objectAtIndex:indexPath.row];
Cosa mettere al posto di ?? e di ???
Grazie
6 Marzo 2011
Pasquale MatriscianoBeh dipende da come è fatta la tua cella personalizzata! Mi verrebbe da dire
UITextView *scroll = (UITextView *)[cell.contentView viewWithTag:1];
scroll.text = [tuoArrayDiTesti objectAtIndex:indexPath.row];
5 Aprile 2011
Renato SorvilloCiao, bellissima guida.
Volevo chiederti, se era possibile collegate ad ogni view del
UITableViewController un immagine.
2 Giugno 2011
Manu MarcoCiao! Bel tutorial, anche io sono più per lo scrivere codice che non farmelo fare, così capisco meglio..però, mi unisco alla richiesta di Buzzo del 20 febbraio dove ti chiedeva la stessa cosa con IB..questo servirebbe a capire come passare da un “ambiente” ad un altro.
La mia domanda qui però è un’altra. Essendo pure io alle prime armi con la programmazione su xcode, ho fatto girare il tuo programma con le view diverse.
Vado su “Tab3”, e ho una lista di voci (iPhone, iPad, iMac, ecc), cliccando su ciascuna delle quali vengo portato a una finestra, uguale per tutte le voci, col nome della voce.
Quel che vorrei fare io, è avere landing diversi per ogni voce cliccata. Ad esempio, clicco iPhone e mi si apre una finestra con 3 pulsanti; clicco iPad, e ho 5 pulsanti (che ovviamente portano da qualche parte, ovvero fanno funzioni diverse).
Come potrei implementare queste “diverse finestre”, a partire da voci della stessa lista-menu?
Grazie!
MM
2 Giugno 2011
Manu MarcoAltra cosa: la tua app NON ruota se giro l’iPad.
Come faccio a farla ruotare, o meglio da dove stabilisco se possa o meno ruotare?
Grazie!
2 Giugno 2011
Pasquale MatriscianoAllora, ti rispondo così su due piedi perché non ho avuto il tempo di rifletterci, ma credo che potresti farlo in diversi modi. Il più semplice, ed anche il meno generale diciamo, è quello di distinguere le varie righe direttamente in “tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath” con uno “switch(indexPath.row)” ed utilizzare un Controller differente a seconda della riga della tabella toccata.
Per gestire l’orientazione basta fare un “return YES” in “shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation” del tuo ViewController.
14 Giugno 2011
GuiGrande tutorial….
Ho però un problema….
nel tab3 come posso fare per visualizzare il testo in una textview e non in una label??
Grazie!
16 Giugno 2011
Pasquale MatriscianoCiao, scusa non capisco qual è il problema. Invece dell’oggetto UILabel hai l’oggetto UITextView che ha la stessa proprietà “text” da impostare… se hai difficoltà spiegati meglio 🙂
27 Ottobre 2011
giovanniio ho realizzato un programma con tab bar e volevo integrare una uinavigationcontroller ma il programma l’ho fatto usando l’IB e non ho idea di come integrarlo 🙁 ho cercato di adattare questo tutoria ma non riesco
14 Dicembre 2011
barbygirlciao, ho un problema, io ho realizzato un’applicazione in cui ho messo nella MianWindows la TabBar. Ogni pulsante mi carica una view. Io vorrei che in ogni view venisse riproposta la TabBar, come posso fare?
14 Dicembre 2011
Pasquale MatriscianoOnestamente non credo di aver ben compreso le tue esigenze!
15 Dicembre 2011
barbygirltranquillo, ho risolto quel problema ma ne ho un’altro, anche se non so se questo è il posto giusto:
io con uno dei pulsant carico l’applicazione nativa della rubrica e ho l’elenco dei numeri di telefono e tutto quello che mi serve (l’ho personalizzata prendendo solo i dati che mi servono), adesso, vorrei che sotto fosse presenta una tab bar come nell’applicazione nativa con i preferiti. Avete idea di come si possa fare?
19 Luglio 2012
Davidegrazie mille. Grazie a questo tutoria ho capito dove sbagliavo a compilare per la versione 3.1, che richiede necessariamente la MainWindow.xib.
23 Luglio 2012
PaskDi nulla, qualsiasi altra domanda chiedi pure 🙂
30 Agosto 2012
CarloHo provato a creare la barra di ricerca con questo metodo ma alla riga
searchController.delegate = self;
mi da un warning:
Assigning to ‘id’ from incompatible type ‘Tab3ViewController *’
Come mai?
31 Agosto 2012
PaskProbabilmente non hai inserito, nel file Header della tua classe UITableViewController, la compatibilità con il protocollo UISearchDisplayController; ovvero una cosa del tipo:
@interface TestTableController : UITableViewController