UISplitView et vue d'authentification/menu
klozen
Membre
Bonjour à tous,
Après avoir longuement cherché sur la toile une solution à mon problème j'en suis arrivé à la conclusion qu'il faut que je me résolve à arranger mon application afin que celle ci soit techniquement réalisable via xCode 4.5 (application pour un IPad).
Le principe est simple, j'aimerais lors de l'ouverture de mon application une vue gérant l'authentification que j'ai déjà créer, une fois loger l'utilisateur se retrouve sur une vue proposant un menu type iCarrousel ou simples boutons n'importe. Ces vue existe déjà et sont déjà implémentées.
Cependant, lors de la sélection d'un menu je souhaiterais arrivé sur un splitView ... Pour prendre un exemple type, au niveau du menu j'ai client et article. Lors de la sélection de client il faudrait arrivé sur un split view implémentant une liste de client dans le master et la fiche client dans la detailview. Cela ca de même pour les articles.
Sur le coup je me suis dit que je pouvais utiliser le même splitview et ne changer que la gestion des données derrière en fonction du menu sélectionné.
Jusque la pas de problème. J'ai fait mes tests les 2 systèmes de vues fonctionnes l'une comme l'autre séparément.
Je décide donc de créer un nouveau projet avec pour template le master détail view que je ne touche pas pour le moment (donc gestion de l'ajout de la date avec affichage de cette date par défaut). J'ajout 2 vues pour l'authentification et le menu. Je place un bouton sur chaque permettant de simuler le login du user sur la première et la sélection du menu sur l'autre.
Ainsi je devrais me retrouver avec ceci :
LoginView ---ModalTransition---> MenuView ---ModalTransition---> DefaultSplitView
Je me heurte donc à plusieurs erreurs.
Déjà le splitView étant implémenter dans l'appDelegate cela ne pouvais que crasher car ma première vue est gérer par un viewController classique.
Je me renseigne donc ... forums, documentation Apple, etc ...
Je découvre petit à petit que finalement le splitView doit être le rootViewController dans le launching de l'application :
[font="Lucida Grande, Geneva, Helvetica, Arial, sans-serif"]Je continue donc à chercher afin de trouver une solution intermédiaire. Je tombe sur un projet de Mat Gommel avec son MGSplitView mais je souhaiterais rester dans les cordes de ce que propose xCode. J'ai également réussi à implémenter une vue (modale) qui s'affiche juste après le chargement de la détailView du split cachant ainsi le splitview. Je fait donc disparaà®tre cette vue une fois le menu sélectionné comme ceci:[/font]
[font="Lucida Grande, Geneva, Helvetica, Arial, sans-serif"]chargement de la vue d'authentification dans la sub configureView du viewDidLoad du DetailViewController du splitView :
[font="Lucida Grande, Geneva, Helvetica, Arial, sans-serif"]Puis lors de la sélection du menu : [/font]
[font="Lucida Grande, Geneva, Helvetica, Arial, sans-serif"]Ce qui m'affiche un message d'erreur, non rédhibitoire puisque pas de crash mais message d'erreur quand même, à chaque affichage de la vue de login : [/font]
Par conséquent j'aurais besoin d'avis éclairé sur la question car il est fort probable que je manque cruellement d'explication théorique sur le fonctionnement de vues séparées ...
Est ce qu'il y a une autre solution pour utiliser le splitView avec authentification et menu ? Est ce que le fait d'utiliser des vues modales comme expliqué ci dessus est correct techniquement parlant ?
Je me dit que c'est tout de même possible car c'est le principe de fonctionnement de l'application "Mes amis" !
Ayant contacté un technicien d'Appel voici sa réponse :
Après avoir longuement cherché sur la toile une solution à mon problème j'en suis arrivé à la conclusion qu'il faut que je me résolve à arranger mon application afin que celle ci soit techniquement réalisable via xCode 4.5 (application pour un IPad).
Le principe est simple, j'aimerais lors de l'ouverture de mon application une vue gérant l'authentification que j'ai déjà créer, une fois loger l'utilisateur se retrouve sur une vue proposant un menu type iCarrousel ou simples boutons n'importe. Ces vue existe déjà et sont déjà implémentées.
Cependant, lors de la sélection d'un menu je souhaiterais arrivé sur un splitView ... Pour prendre un exemple type, au niveau du menu j'ai client et article. Lors de la sélection de client il faudrait arrivé sur un split view implémentant une liste de client dans le master et la fiche client dans la detailview. Cela ca de même pour les articles.
Sur le coup je me suis dit que je pouvais utiliser le même splitview et ne changer que la gestion des données derrière en fonction du menu sélectionné.
Jusque la pas de problème. J'ai fait mes tests les 2 systèmes de vues fonctionnes l'une comme l'autre séparément.
Je décide donc de créer un nouveau projet avec pour template le master détail view que je ne touche pas pour le moment (donc gestion de l'ajout de la date avec affichage de cette date par défaut). J'ajout 2 vues pour l'authentification et le menu. Je place un bouton sur chaque permettant de simuler le login du user sur la première et la sélection du menu sur l'autre.
Ainsi je devrais me retrouver avec ceci :
LoginView ---ModalTransition---> MenuView ---ModalTransition---> DefaultSplitView
Je me heurte donc à plusieurs erreurs.
Déjà le splitView étant implémenter dans l'appDelegate cela ne pouvais que crasher car ma première vue est gérer par un viewController classique.
Je me renseigne donc ... forums, documentation Apple, etc ...
Je découvre petit à petit que finalement le splitView doit être le rootViewController dans le launching de l'application :
A split view controller must always be the root of any interface you create. In other words, you must always install the view from aUISplitViewController object as the root view of your application's window. The panes of your split view interface may then contain navigation controllers, tab bar controllers, or any other type of view controller you need to implement your interface. Split view controllers cannot be presented modally.
[font="Lucida Grande, Geneva, Helvetica, Arial, sans-serif"]Je continue donc à chercher afin de trouver une solution intermédiaire. Je tombe sur un projet de Mat Gommel avec son MGSplitView mais je souhaiterais rester dans les cordes de ce que propose xCode. J'ai également réussi à implémenter une vue (modale) qui s'affiche juste après le chargement de la détailView du split cachant ainsi le splitview. Je fait donc disparaà®tre cette vue une fois le menu sélectionné comme ceci:[/font]
[font="Lucida Grande, Geneva, Helvetica, Arial, sans-serif"]chargement de la vue d'authentification dans la sub configureView du viewDidLoad du DetailViewController du splitView :
[/size][/font]<br />
[font="Lucida Grande, Geneva, Helvetica, Arial, sans-serif"][size="2"][self performSegueWithIdentifier:@"goLog" sender:self];[/size][/font]<br />
[font="Lucida Grande, Geneva, Helvetica, Arial, sans-serif"][size="2"]
[/font][font="Lucida Grande, Geneva, Helvetica, Arial, sans-serif"]Puis lors de la sélection du menu : [/font]
<br />
[font="Lucida Grande, Geneva, Helvetica, Arial, sans-serif"][size="2"][self dismissViewControllerAnimated:YES completion:nil];<br />
[/size][/font][font="Lucida Grande, Geneva, Helvetica, Arial, sans-serif"]Ce qui m'affiche un message d'erreur, non rédhibitoire puisque pas de crash mais message d'erreur quand même, à chaque affichage de la vue de login : [/font]
Unbalanced calls to begin/end appearance transitions for <UISplitViewController : 0x1fd56f60>.
Par conséquent j'aurais besoin d'avis éclairé sur la question car il est fort probable que je manque cruellement d'explication théorique sur le fonctionnement de vues séparées ...
Est ce qu'il y a une autre solution pour utiliser le splitView avec authentification et menu ? Est ce que le fait d'utiliser des vues modales comme expliqué ci dessus est correct techniquement parlant ?
Je me dit que c'est tout de même possible car c'est le principe de fonctionnement de l'application "Mes amis" !
Ayant contacté un technicien d'Appel voici sa réponse :
[font=arial, sans-serif]Segueing to a Split View Controller is unsupported. As per the "View Controller Catalog" guide:[/font]
[font=arial, sans-serif]"A split view controller must always be the root of any interface you create. In other words, you must always install the view from a UISplitViewController object as the root view of your application's window". You should re-work your interface to either move the UISplitViewController to the root of your UI or avoid using UISplitViewController. One way to implement the former option is to present the authentication and menu modally when the app is first launched. Once the user has provided the appropriate information, you can dismiss the modal view controller to reveal the split view controller.[/font]
Merci d'avoir pris le temps de me lire /thumbsup.gif' class='bbc_emoticon' alt=' ' />
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
1) mettre UISplitViewController en root de la fenêtre et donc, afficher l'écran de login et le carrousel dans un VC modal.
2) se passer de UISplitViewController.
UISplitViewController n'est pas une classe très réussie. Notamment, sa gestion des UIBarButonItems lors de l'affichage/masquage du panneau latéral m'a posé de nombreux problèmes. Je serais donc d'avis d'utiliser le code de Mattt Gemmel, qui est une sommité dans notre microcosme.
Par ailleurs, si l'appli ne fonctionne qu'en orientation horizontale, implémenter ce mécanisme toi-même n'est pas sorcier.
Au passage, je salue l'effort de recherche de d'argumentation (j'avoue n'avoir que survolé) pour un premier post sur le forum, c'est rare.
Alors voila après quelques tests j'ai mis la (demi) solution suivante en place (avec storyboard) :
L'inconvénient est que c'est une vue modale, donc lors de la déconnexion et d'une reconnexion avec un login différent, et bien on atterris à la ou le dernier utilisateur s'est déconnecté. Par conséquent cela va provoquer quelques problèmes de droits ...
L'idéal serais un push segue lors de la déconnexion seulement on en revient au problème du splitView qui ne supporte pas une navigation qui n'est pas inhérente à son fonctionnement.
Il faudrait peut-être effectué un refresh complet splitView lors d'une connexion ==> je teste ca demain.
ou alors peut-etre qu'il est possible de faire un replace au lieu d'un appel modal de la vue afin de l'afficher dans le detail view. Il suffirait après de "bloquer" temporairement l'accès à la master view en la désactivant ou en la cachant. C'est prévu dans le splitViewcontroller ? ==> je vais tester ca demain également.
Sinon j'avais également réussi en insérant une vue d'authentification créer dans un fichier .xib et qui était appelé et détruite dans l'appDelegate.
Dans les 2 cas on se retrouve avec se problème d'initialisation du split lors de la déconnexion / reconnexion.
Personnellement j'ai l'impression que cette "technique" avec une vue modale est un peu barbare mais je me dit que ca doit être courant dans les applications ipad qui utilise le splitView ... On peut prendre l'exemple de l'application (native ?) "Mes amis" qui effectue une authentification avant d'afficher des vues séparées ...
Je vous tiens au courant de l'avancé, mais si vous avez des infos concernant mes interrogations précédentes je suis preneur de toutes informations /wink.png' class='bbc_emoticon' alt=';)' />
ça a l'air de rien mais beaucoup de nouveaux sur les forums viennent le bec ouvert sans chercher ou expliquer ce qu'ils ont testé et en espérant en réponse la solution avec le code tout cru, au lieu de commencer par chercher eux-même, expliquer leur démarche, etc.
Ce n'est pas ton cas au contraire et c'est assez rare pour être signalé, et on dit toujours quand ça va pas jamais quand ça va bien, donc cette fois je le dit, merci, c'est apprécié ;-)
Pas de problème c'est normal /wink.png' class='bbc_emoticon' alt=';)' />
Je vois trop de forums avec des topics vide de sens par le fait que le créateur demande du code comme tu le dit si bien /wink.png' class='bbc_emoticon' alt=';)' /> , ou alors que les réponses s'apparentent à des citations de doc alors que la plus part du temps il est recherché une explication autre que la doc officielle car justement la doc officielle n'a pas été comprise...
Du coup je me dit qu'une explication maison en français sur mon problème ça peut pas faire de mal surtout que les explications à se sujet sont souvent en anglais ...
Par ailleurs je vous joins 2 projet et leur code source respectif.
Le fichier SplitViewControllerWithLogin contient un projet brut envoyé par un technicien d'Apple pour appuyé son explication sur le principe de la vue modal qui cache le splitView. Le code est donc plus clair avec plus de commentaire. C'est une très bonne base je trouve à une exception près (et oui il y a toujours un "mais" /wink.png' class='bbc_emoticon' alt=';)' /> )
Et oui car qui dit Login dit déconnexion puis (re)login ! Du coup je m'atèle et en partant du code source reçu je monte un projet vite fait avec un masterView modifier (tabbar) et du coup un bouton déconnexion (vous trouverez ca dans le fichier Split_V8)
bref le login est fonctionnel, la navigation aussi : affichage/ajout/modification de l'heure avec le template de base puis ajout d'un tabbar dans la masterView pour gérer une autre liste de donnée sur laquelle il y a une cellule (en dur pour le test bien entendu) qui affiche également un texte dans la vue détail du splitView. Cette masterView posséde également un bouton déconnexion qui finalement ne fait qu'afficher la vue login. Qui elle à son tour se dismiss lors du login.
Le problème est celui évoqué dans le post précédent. Donc je me remet au boulot et vous tiens au courant /wink.png' class='bbc_emoticon' alt=';)' />
Excepté ce problème les versions jointes devrait être fonctionnelle /clap.gif' class='bbc_emoticon' alt=' ' />
Pour l'heure j'ai une quesiton à propos de ce storyboard :
Cela afin de vérifier le changement d'onglet et c'est le drame !! /crybaby.gif' class='bbc_emoticon' alt=' ' />
Je m'aperçoit que la sub n'est même pas appelé. Bon direct je vais vérifier mon .h et je vais ajouter dans l'interface : (j'ai tellement de fois oublié d'ajouter ces delegate que maintenant dès que j'ai un problème de sub qui n'est pas appelé que je regarde ca direct)
Cependant cela n'y change rien du tout /crybaby.gif' class='bbc_emoticon' alt=' ' /> /crybaby.gif' class='bbc_emoticon' alt=' ' />
Bon du coup je me dit que j'ai du mal initialiser quelque chose. Je fait des modif dans le storyboard au niveau des segue, je met un navigationController unique suivis du tabbar mais rien n'y fait.
Du coup j'essaye ca :
placé dans le viewDidLoad de la masterView.
Et la et bien ca fonctionne ! /crazy.gif' class='bbc_emoticon' alt=' ' />
Donc ce que j'en conclue c'est que j'accède aux éléments de mon tabbarController mais pas aux fonctions liées à ce dernier ... oO ?!
Ca me semble être une erreur de delegate, par conséquent je pense qu'il faudrait changé ou ajouter une attribution de delegate.
Peut-être appliquer une delegate tabbar au splitView comme il est fait pour un navigationController dans l'AppDelegate sauf que en faisant et bien c'est simple le tabbar supplante le navigationController /xd-laugh.gif' class='bbc_emoticon' alt='xd' />
Donc je dois loupé une étape ou peut être simplement un ordre d'initialisation donc si vous avez une petite explication sous le coude elle seras (vraiment) la bienvenue /smile.png' class='bbc_emoticon' alt=':)' />
Puis pendant que j'y suis, une simple question technique : est ce que c'est judicieux d'utiliser pour les 2 masterView le même controller (c'est à dire les même fichier .h et .m) et ainsi faire la différence entre les 2 via l'outlet de chaque tableview ?
Mais tu n'as pas pour autant indiqué à ton TabBarViewController ou ton TabBar que son delegate c'est ton MasterViewController.
Il faut bien faire l'association quelque part, pour qu'il sache de quelle TabBar il est le delegate. Ou plutôt dans l'autre sens que la TabBar sache quel objet (se conformant au UITabBarDelegate) est son delegate.
Tu peux très bien imaginer avoir 2 TabBar dans ton appli, et également 2 UIViewController que tu auras déclaré se conformer au protocole <UITabBarDelegate>, il faut quand même que tu dises à un moment que la TabBar 1 est associée au ViewController A ou B, et de même pour la TabBar 2.
Donc il faut que tu affectes la propriété "delegate" de ta UITabBar à l'instance de ton MasterViewController, pour qu'il en soit le delegué et que la TabBar appelle les méthodes sur ce dernier pour le prévenir quand un onglet a changé. (Ou affecter la propriété "delegate" de ton UITabBarController à l'instance de ton MasterViewController, ça dépend si dans ta logique c'est la TabBar ou le TabBarViewController qui informe son delegate le MasterVC).
Bien sûr pour faire cette affectation, tu peux le faire par code, ou tu peux le faire dans ton XIB/Storyboard, puisque la propriété "delegate" est en général marqué comme IBOutlet et est donc accessibles depuis InterfaceBuilder pour la connecter à un objet directement par IB.
Oui lorsque je visualise pour le splitview ainsi que pour la tabbar aucun delegate n'est enregistrer dans la liste des "connections inspector"
Cependant il n'est pas possible d'affecter cet "Outlet" delegate à l'un comme à l'autre.
Dans mon cas c'est dans le split que le tabbar doit etre associer en tant que delegate étant donné que le tabbar ne s'applique qu'a la masterView ou alors je fait fausse route dès cette réflexion ?
Puis le fait d'avoir relier mon tabbarController directement au splitView avec la notion de MasterView Controller pour le segue ca ne lui suffit pas pour indiquer que le tabbar fait partit intégrante du splitView ?
Cette solution ne fait pas d'erreur à la compile mais du coup me cache mon bouton "Master" dans ma vue détailView mais on y a toujours accès via le landscape et cela fonctionne toujours. Cependant le tabbar n'est toujours pas delegate pour autant.
Ce qu'il te faut faire c'est l'inverse, dire que quand ta TabBar fait des choses (change d'onglet, etc), indiquer qui elle doit prévenir (qui est son delegate), en l'occurrence ton SplitVC. Donc dire que tabbar.delegate = splitViewController. Pas l'inverse comme tu as fait.
Concrètement quand le UITabBarController va changer d'onglet, sous le capot ça va faire [tabbar.delegate didSelectItem:newItem] donc appeller didSelectItem sur l'objet qui est affecté à la propriété "delegate" du tabBar. Donc c'est bien la propriété delegate du tabBar qu'il faut associer à ton SplitVC, tu veux que ce soit lui qui soit prévenu quand la TabBar change d'onglet. Pas le delegate de la SplitVC qu'il faut affecter.
Mais dans ce cas pourquoi il n'est pas possible dans le storyboard de définir le delegate de ma tabbarcontroller avec mon splitView ?
c'est à dire ctrl+clic sur mon tabbarController puis relancher sur mon splitViewController.
J'avais commencer à faire un myTabbarViewController ce qui me permet de récupérer le changement d'onglet dans ce controller mais pas dans le masterview...
(navigationViewController <---delegate--- splitViewController) <---delegate--- tabbarController <---delegate--- navigationController <---delegate--- uiTableView
et celui qui me pose problème ca serais celui en gras sachant que ce qui est entre parenthèse est ce qui est fait par d"faut avec le template master détails de xCode.
Sous classer c'est à dire créer une classe perso qui colle au protocol du splitView et qui me permettra de coller également au protocol du UITabBarControllerDelegate ?
Avec le pseudo-schema que tu viens de faire tu est parti pour dire que tu veux que le delegate de ton tabbarController soit le splitViewController. Pour pouvoir faire cela, il faut que le splitViewController se conforme au protocole UITabBarControllerDelegate, et que tu implémentes dans splitViewController les méthodes "tabBarController:didSelectViewController:" et autres méthodes du protocole UITabBarControllerDelegate.
Si ça ne t'arrange pas parce que ça t'impose de sous-classer UISplitViewController (pour pouvoir lui ajouter lesdites méthodes) et que tu n'avais pas prévu de le sous-classer, rien ne t'empêche d'utiliser quelqu'un d'autre comme delegate pour ton TabBarController, par exemple le navigationViewController. Il est déjà delegate de ton UISplitViewController mais rien ne l'empêche d'être aussi delegate de UITabBarController aussi, et de gérer les deux.
Comme tu as déjà certainement sous-classé ce navigationViewController (c'est lui ton MasterViewController ?) pour lui rajouter des méthodes, tu peux en rajouter d'autres pour aussi implémenter UITabBarControllerDelegate. Et rajouter dans son .h qu'il se conforme au protocole UITabBarControllerDelegate. Et l'affecter via IB comme delegate de ton TabBarController (tout comme il est déjà affecté aussi comme delegate du UISplitViewController).
Dire qu'un objet A est delegate d'un autre objet B, c'est dire que quand B a quelquechose à déléguer (ça peut être soit une question à poser "est-ce que j'ai le droit de changer d'onglet ?", ou une information "ça y est j'ai changé d'onglet" ou ce genre de choses, ça dépend de ce qui est prévu dans le protocole en question), c'est A qu'il prévient, c'est à A qu'il demande.
Quand une TableView a besoin d'une cellule, c'est à son dataSource qu'elle demande, quel que soit l'objet qui sert de dataSource. Quand tu cliques sur une cellule, c'est l'objet qui est affecté comme étant son delegate qu'elle prévient qu'une cellule a été cliquée. Quel que soit cet objet qui sert de delegate. Bah là c'est pareil.
Et rien n'empêche un objet A d'être à la fois delegate de B (un UISplitViewController qui va prévenir son delegate quand le ViewController "Master" est masqué car l'iPad a tourné entre autres) et delegate de C (un UITabBarController qui va prévenir son delegate quand il a changé d'onglet pour afficher un autre ViewController) !
Franchement merci d'avoir pris le temps de m'expliquer ce principe qui était un peu (trop) flou dans mon esprit /wink.png' class='bbc_emoticon' alt=';)' />
Par contre juste un hic par rapport au fait que le navigationController est sous classer car delegate du splitView.
Je suppose que ca fait référence à cette ligne
Mais il vient d'ou ? Il est juste présent dans le code car indispensable au splitView ? (car pas de trace dans le storyboard)
Ce navigationController est la car c'est le template de master detail de xCode qui l'a crée...
Mais pour moi mon RootController c'est mon splitView ...
Le fait que le navigationController soit le delegue de mon splitView ca me permet de récupérer les infos de ma masterView et détailView ? Donc un splitView c'est 2 vues séparées qui répondent au protocole du splitView et rendent des compte au navigationController pour gérer les actions inhérentes tel que le passage du mode portrait au landscape, etc ?
Du coup pour ce principe de delegate je comprend mieux pourquoi par exemple il faut relier un textField à la vue qui le contient /tongue.png' class='bbc_emoticon' alt=':P' /> ou encore comme tu le dit une cell et sa tableView /smile.png' class='bbc_emoticon' alt=':)' />
et du coup ca fonctionne je récupère bien les évènement du tabbarController du style
mais toujours pas l'évènement didSelectItem qui lui découle du tabBar ...
Mais si on gère le tabbarController on ne devrait pas gérer en même temps le tabbar à l'intérieur ?!
Non, pas à sa vue, à son view controller, qui va se conformer au protocole UITextFieldDelegate.
Une UIView est un objet qui s'affiche à l'écran et gère les événements. Un UIViewController gère une UIView racine (qui elle même peut contenir des UIView enfants). Même si par abus de langage on dit parfois que "le view controller s'affiche", concrètement c'est sa vue qui s'affiche.
Tu comprendras que le délégué du text field n'est pas obligatoirement un view controller (même si c'est souvent le cas), ça pourra être n'importe quel objet se conformant au protocole.
J'ai donc remodelé mon storyboard afin que ca donne ceci :
UISplitViewController n'est pas bien compliqué à utiliser (sauf quand on modifie la barre de boutons, mais c'est un cas particulier).
À l'issue de la formation, j'encourage les stagiaires à s'intéresser à Storyboard seuls de leur côté. Une fois les concepts sous-jacents assimilés, l'utilisation de Storyboard se révèle simple et on comprend ses limitations. Si jamais Storyboard ne répond pas au besoin (ce qui arrive souvent), il nous reste la possibilité de gérer les choses à la mano.
J'ai donc 2 vues initialiser dans l'appDelegate avec l'ajouts de ces vues dans le viewcontrollers du tabbar initialisé également dans l'appdelegate, etc. Tout fonctionne, j'ai bien défini le delegate pour récupérer les évènements du tabbarViewcontroller dans mes vue.
Par contre je ne peut pas récupérer les évènements du tabbar du type -(void)tabbar didSelectItem est ce normal ? La tabbar n'est pas lié au tabbar ? Il faut que l'ajout dans les fichier xib pour pouvoir récupérer ces évènements ?
Si tu veux savoir quand l'utilisateur change d'onglet, mets-toi en délégué du UITabBarController.
Rien compris.
Un objet appelle les méthodes déléguées de son... délégué.
Une UITabBar appelle les méthodes du protocole UITabBarDelegate de son délégué.
Un UITabBarController appelle les méthodes du protocole UITabBarControllerDelegate de son délégué.
Le délégué du UITabBarController est ta sous-classe de UIViewController.
Mais le délégué de la UITabBar est le UITabBarController.