• 12 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 2/26/20

Remplissez le sélecteur

Log in or subscribe for free to enjoy all this course has to offer!

Dans le chapitre précédent, nous avons créé l'interface de notre application, mais malheureusement le sélecteur a échappé à notre folie artistique ! Nous n'avons pas pu le configurer dans le storyboard. Et du coup, quand vous lancez l'application, le résultat en la matière n'est pas probant...

Qu'à cela ne tienne, nous aurons sa peau dans le code !

Delegate, Datasource et MVC

En MVC, vous savez qu'il existe plusieurs formes de communication entre les trois parties. Ce schéma doit vous rappeler quelque chose :

Notamment, on y voit que la vue communique avec le contrôleur via les outlets et les actions. Nous allons découvrir ici deux nouvelles formes de communication : les datasource et les delegate.

Le dataSource

En MVC, une vue ne détient pas ses données. Car une vue n'a qu'un rôle d'affichage, ce n'est pas son rôle de savoir quoi afficher. C'est le contrôleur qui va lui dire.

Ainsi, dans le cas de notre liste de races, ce n'est pas la vue qui doit retenir la liste de races, c'est le contrôleur qui va lui dire quoi afficher. Et il va tirer cette information du modèle qui détient les données.

Donc pour savoir quoi afficher, le contrôleur va simplement utiliser des outlets pour les vues relativement simples et surtout qui ont peu de données à afficher. Mais pour des vues plus complexes avec beaucoup de données à afficher, le contrôleur va se positionner en source de données pour que la vue puisse piocher dedans et donc n'avoir en même temps que très peu de données à afficher.

Le contrôleur est donc le dataSource, celui qui détient les données. Et voilà comment cela va fonctionner :

  1. Le PickerView va nommer le contrôleur source de données.

  2. Cela implique que le contrôleur s'engage à répondre à certaines questions précises du PickerView, par exemple, combien d'éléments y a-t-il dans la liste ?

  3. Lorsque la vue en a besoin, le contrôleur répond aux questions.

Vous venez de découvrir une nouvelle forme de communication aveugle entre le contrôleur et la vue.

Le delegate

Le delegate fonctionne de la même manière. Une vue peut avoir besoin de poser des questions à son contrôleur selon les évènements qui lui arrivent.

Mais parfois, on ne veut pas faire toujours la même action. Par exemple, lorsque l'utilisateur va faire défiler la liste des races, la vue va devoir demander à chaque fois : quel est le prochain nom de race que je dois afficher ? Et à chaque fois, le contrôleur va répondre une race différente. C'est lui qui choisit ce qu'on affiche.

Pour prendre un autre exemple, on peut parler des scroll view. Une scroll view va utiliser le mécanisme de delegate pour dire au contrôleur :

  • Je viens de scroller de quelques pixels, tu veux faire une action ?

  • Je viens d'atteindre la fin du scroll, on fait quelque chose ?

  • Je viens de m'arrêter de scroller, que veux-tu faire ?

Autrement dit, la vue délègue toute la prise de décision au contrôleur. D'où le nom de ce mécanisme.

Le contrôleur devient ce qu'on appelle le delegate, celui à qui est déléguée la responsabilité. Et cela va fonctionner exactement comme pour le data source :

  1. Le PickerView va nommer le contrôleur délégué.

  2. Cela implique que le contrôleur s'engage à répondre à certaines questions précises du PickerView.

  3. Lorsque la vue en a besoin, le contrôleur répond aux questions.

Encore une nouvelle forme de communication aveugle entre le contrôleur et la vue. Vos compétences en MVC ont fait un bond en avant !

Ces 3 étapes vont être les trois étapes que nous allons suivre pour configurer le delegate et le dataSource de notre PickerView.

Nommez le dataSource et le delegate

Lors de la première étape, la vue nomme le contrôleur son dataSource et son delegate. Et nous allons faire cela avec... deux control-drags !

Il vous suffit de faire le control-drag depuis le Picker View vers le contrôleur comme ceci :

Une pop-up apparaît. Cliquez sur dataSource puis répétez l'opération et cliquez cette fois sur delegate.

Le contrôleur s'engage à répondre aux questions

Deuxième étape : le contrôleur s'engage à répondre aux questions de la vue. Pour cela, le contrôleur va implémenter ce qu'on appelle un protocole.

Un protocole, c'est un outil en Swift dont nous n'avons pas encore parlé. Un protocole est une liste de méthodes vides et de propriétés.

De méthodes vides ?

Oui un protocole, c'est juste une liste de méthodes vides. Contrairement à une classe dans laquelle, on écrit une méthode et son implémentation, dans un protocole, on n'a que la déclaration des fonctions.

Pour vous donner un exemple, voici le protocole UIPickerViewDataSource.

protocol UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int
}

C'est juste une liste de méthodes.

À quoi ça sert ?

Justement, ça va nous être très utile ici. On veut que le contrôleur s'engage à répondre à des questions. Et les questions, ce sont simplement les méthodes du protocole !

Pour cela, notre contrôleur va se conformer au protocole. C'est un terme technique pour dire qu'il s'engage à fournir une implémentation aux méthodes qui se trouvent dans le protocole.

Pour concrétiser cet engagement, il suffit d'ajouter le nom du protocole au moment de la déclaration de notre classe, comme ceci :

class FormViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {
}

On rajoute les protocoles après la super classe, si elle existe, et on les sépare par des virgules.

Une fois que vous avez écrit cela, vous devriez voir des erreurs s'afficher.

Type 'FormViewController' does not conform to protocol 'UIPickerViewDataSource'

Le problème, c'est qu'on s'engage à implémenter des méthodes, mais on ne le fait pas ! Xcode n'est pas content !

Résolvons cela.

Le contrôleur répond aux questions

Il ne nous reste plus qu'à répondre aux questions. Et pour cela, nous allons implémenter les méthodes de nos deux protocoles : UIPickerViewDataSource et UIPickerViewDelegate.

Méthodes du dataSource

La première, c'est donc :

func numberOfComponents(in pickerView: UIPickerView) -> Int {
}

Ajoutez cette fonction dans le code du FormViewController. Nous allons l'implémenter. Cette méthode doit apparemment renvoyer un entier. Cet entier correspond au numberOfComponents de notre PickerView.

C'est quoi les components du PickerView ?

Les components représentent les différentes colonnes de notre PickerView. Souvenez-vous, le PickerView fonctionne comme la roulette au casino. Par exemple, sur la roulette suivante, il y a quatre components.

Le nôtre est bien plus simple puisqu'on veut ajouter seulement une liste, celle des races de chiens.

Donc on va répondre simplement à la question en implémentant la méthode comme ceci :

func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}

Maintenant, la vue sait combien de components afficher.

Passons maintenant à la deuxième méthode :

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
}

Cette méthode retourne également un entier. Cette fois il correspond au nombre d'éléments présent dans chaque colonne. C'est la raison pour laquelle nous avons component en paramètre, pour pouvoir adapter la réponse en fonction de la colonne.

Nous nous n'avons qu'une seule colonne, donc on va simplement répondre par le nombre de races de chiens à afficher. Et pour cela, nous allons tout simplement utiliser le tableau dogRaces qui se trouve dans notre modèle.

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return dogRaces.count
}

Et voilà ! La vue connaît maintenant le nombre d'éléments à prévoir dans la liste.

Méthode du delegate

UIPickerViewDelegate est un protocole qui contient bien plus de méthodes qui permettent de personnaliser complètement la vue. Mais il y en a une seule qui nous intéresse vraiment, c'est celle-ci, que je vous invite à rajouter dans votre code :

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
}

Cette méthode renvoie un String optionnel qui correspond au titre que l'on veut mettre pour chaque élément. Évidemment, ce titre dépend de la colonne et de la ligne dont on parle. C'est la raison pour laquelle nous avons les entiers row et component en paramètres de cette méthode.

Encore une fois, le paramètre component ne nous importe pas puisque nous n'avons qu'une seule colonne. En revanche, on va utiliser le paramètre row en index de notre tableau dogRaces.

Vous donc implémenter la méthode comme ceci :

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return dogRaces[row]
}

Et voilà ! Maintenant la vue sait quel titre afficher en fonction de la ligne à laquelle on se trouve, vous pouvez lancer l'application et confirmer que tout fonctionne correctement !

Voici le code complet de la classe FormViewController :

class FormViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return dogRaces.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return dogRaces[row]
}
}

Résumé

  • En MVC, une vue peut utiliser le mécanisme du dataSource pour ne pas être propriétaire de ses données et les réclamer au contrôleur.

  • En MVC, une vue peut utiliser le mécanisme du delegate pour déléguer les prises de décision au contrôleur.

  • Un protocole est une liste de méthodes vides et de propriétés.

  • Pour utiliser le mécanisme de dataSource ou delegate, on suit trois étapes :

    1. La vue nomme le contrôleur son dataSource et/ou delegate.

    2. Le contrôleur s'engage à répondre aux questions de la vue en adoptant le protocole correspondant.

    3. Le contrôleur répond aux questions de la vue en se conformant au(x) protocole(s) et donc en implémentant les méthodes de ce dernier.

Dans le prochain chapitre, nous allons revenir sur nos champs de texte et apprendre à gérer le clavier !

Example of certificate of achievement
Example of certificate of achievement