• 12 heures
  • Difficile

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 01/02/2019

Appliquez le delegate pattern

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Notre Table View est bien installée, mais, pour l'instant, elle est complètement vide. Cela ne va pas durer ! Dans ce chapitre, je vais vous présenter le mécanisme qui va nous permettre de la remplir : le delegate pattern !

Présentation du delegate pattern

Commençons par faire un retour sur le MVC. Le MVC, pour l'instant, doit ressembler à ceci pour vous :

Avec les outlets, le contrôleur peut donner à la vue les données dont elle a besoin pour s'afficher. Cette méthode fonctionne bien, mais a ses limites. Elle ne marche que pour de petites quantités de données.

Or, comme on l'a vu, une liste peut avoir des tonnes de données ! On ne va pas tout donner à la vue en lui demandant de se débrouiller avec. La vue ne doit détenir que les données qui lui permettent de faire l'affichage, car c'est son seul rôle.

En conséquence, la vue va devoir demander régulièrement au contrôleur de lui donner de nouvelles données. À chaque fois que l'on fait défiler la vue, elle va réclamer de nouvelles données au contrôleur.

Le problème, c'est que ma Table View ne sait pas avec quel contrôleur elle va travailler. Ici, nous utilisons notre ListViewController qui présente une liste de jouets, mais ailleurs, nous pourrions en utiliser un autre qui fournit des listes de réglages, ou des listes de contacts...

Pour faire fonctionner notre Table View, on doit donc résoudre le problème suivant :

  1. Ma Table View doit pouvoir être informée de la composition de la liste par le contrôleur.

  2. N'importe quel objet doit pouvoir faire ce travail. Ma Table View se moque de savoir avec qui elle travaille, et cela me permet de la réutiliser dans de multiples situations.

Pour résoudre ce double problème, on va utiliser le delegate pattern. On dit en effet que la Table View délègue une partie de son fonctionnement à un autre objet. Et au cœur du delegate pattern, on va voir ce que nous avons étudié dans la partie 1 : un protocole !

Le delegate pattern est une nouvelle méthode de communication aveugle entre la vue et le contrôleur.

Et voici comment cela fonctionne :

  1. On crée une liste de questions que la vue peut poser.

  2. La vue nomme un objet son delegate, en l'occurrence notre contrôleur.

  3. Le contrôleur s'engage à répondre aux questions sur la liste.

  4. Le contrôleur répond effectivement aux questions.

Delegate pattern et protocoles

Détaillons maintenant ces 4 étapes en rentrant dans le détail du protocole.

1. On crée une liste de questions que la vue peut poser.

La liste de questions est une liste d'exigences en fait. Donc ici, on parle de la création d'un protocole. Pour UITableView, ce protocole se nomme UITableViewDataSource , car c'est la source de données.

protocol UITableViewDataSource: class {
    func numberOfSections(in tableView: UITableView) -> Int
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
    // (...)
}

2. La vue nomme un objet son delegate, en l'occurrence notre contrôleur.

UITableView a une propriété dataSource de type UITableViewDataSource :

class UITableView: UIScrollView {
    weak var dataSource: UITableViewDataSource?
}

Cette propriété est utilisée à l'intérieur de la classe UITableView pour appeler les méthodes du protocole au moment où la Table View en a besoin. Comme promis, notre Table View se fiche bien de savoir qu'objet fera office de dataSource. Elle a juste besoin de savoir qu'il répondra aux exigences de notre protocole.

Ensuite, cette propriété prend pour valeur le contrôleur :

class ViewController: UIViewController {

    var tableView: UITableView

    override func viewDidLoad() {
        super.viewDidLoad()
        // J'assigne le contrôleur comme valeur de la propriété dataSource.
        tableView.dataSource = self
    }
}

3. Le contrôleur s'engage à répondre aux questions sur la liste.

Le contrôleur va ici adopter le protocole UITableViewDataSource :

class ViewController: UIViewController, UITableViewDataSource {
}

4. Le contrôleur répond effectivement aux questions.

Le contrôleur implémente les méthodes de UITableViewDataSource :

class ViewController: UIViewController, UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // (...)
    }
}

Vous venez de découvrir un nouveau mode de communication aveugle entre la vue et le contrôleur :

Mise en place du dataSource !

Mettons toute cette théorie en application dans notre code.

2. La vue nomme un objet son delegate, en l'occurrence notre contrôleur.

Pour que la Table View nomme le contrôleur son dataSource, on peut faire de notre Table View un outlet de ListViewController et ensuite recopier le code que je vous ai donné au-dessus.

Mais nous allons faire encore plus simple en utilisant le control drag !

Faites un control drag dans le storyboard depuis la Table View vers le contrôleur :

Et voilà, vous venez de nommer votre contrôleur, le dataSource de la Table View.

3. Le contrôleur s'engage à répondre aux questions sur la liste.

Comme on l'a vu à cette étape, nous allons faire adopter le protocole UITableViewDataSource à notre contrôleur ListViewController :

class ListViewController: UIViewController, UITableViewDataSource {}

Lorsque vous faites adopter un protocole à une classe, je vous suggère d'utiliser une extension par protocole, donc on va légèrement modifier notre code comme ceci :

class ListViewController: UIViewController {}

extension ListViewController: UITableViewDataSource {}

4. Le contrôleur répond effectivement aux questions.

Ensuite, nous allons implémenter les méthodes du protocole pour nous y conformer correctement. Nous n'allons en implémenter que trois, car les autres sont optionnels.

La première méthode que nous allons implémenter s'appelle numbersOfSection :

extension ListViewController: UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
}

Cette méthode permet de préciser à la Table View le nombre de sections dont nous allons avoir besoin. Dans notre cas, nous ne voulons pas séparer notre code selon des sections, donc nous allons simplement renvoyer 1 pour avoir une seule section.

La deuxième méthode se nomme numbersOfRowsInSection :

extension ListViewController: UITableViewDataSource {
    // (...)

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return ToyService.shared.toys.count
    }
}

Elle permet de préciser le nombre de cellules que l'on veut pour chaque section. Dans notre cas, on veut autant de cellules que nous avons d'éléments dans notre tableau de jouets toys.

La troisième méthode va nous permettre de préciser le contenu de chaque cellule. Je vous propose que l'on voie cela ensemble dans le prochain chapitre !

En résumé

  • La delegate pattern est une communication aveugle entre la vue et le contrôleur. Elle s'organise en 4 étapes :

    1. On crée une liste de questions que la vue peut poser.

    2. La vue nomme un objet son delegate, en l'occurrence notre contrôleur.

    3. Le contrôleur s'engage à répondre aux questions sur la liste.

    4. Le contrôleur répond effectivement aux questions.

  • La liste de questions est en fait un protocole auquel se conforme le contrôleur.

  • Dans l'étape 2, on peut utiliser directement le control drag pour nommer le contrôleur le dataSource.

Dans le prochain chapitre, nous allons remplir notre Table View en précisant le contenu de nos cellules !

Exemple de certificat de réussite
Exemple de certificat de réussite