Les classes UITableView et UICollectionView permettent l’affichage d’une liste d’éléments soit sur une ou sur plusieurs colonnes.
Exemples:
La classe UITableView permet l’affichage d’une liste d’éléments sur une seule colonne.
UITableView est une sous-classe de UIScrollView, qui permet aux utilisateurs de faire défiler les éléments de la table.
C’est une classe idéale lorsqu’il est nécessaire d’afficher une grande quantité de données sous la forme d’un tableau.
Par défaut, UITableView propose des cellules qui contiennent un titre, un sous-titre, une image à gauche et un accessoire à droite.
Voici un exemple d’un UITableView avec un titre, sous-titre et une image:
Voici un exemple d’un UITableView avec un accessoire:
UITableView et UICollectionView proposent deux protocoles: dataSource et delegate (plus prefetchDataSource pour UICollectionView) .
Il est obligatoire de souscrire au protocole dataSource pour lier les contrôles à une source de données.
Par exemple, si nous voulions utiliser un UICollectionView sur une scène, il faudrait ajouter UICollectionViewDataSource à la suite du nom de la super classe du contrôleur de la scène:
class ViewController: UIViewController, UICollectionViewDataSource {
// et
viewDidLoad(){
unCV.dataSource = self
}
Les données à afficher, via UITableVite et UICollectionView peuvent provenir de trois sources:
À cette étape, nous allons créer une application qui affiche, via un UITableView, les enregistrements d’un tableau (Array) local.
Action 1.0 – Téléchargeons les ressources du projet
Action 1.1 – Créons un nouveau projet « Les amis de la science »
Action 1.2 – Ajoutons, dans le groupe ‘Ressources’, les ressources du projet (téléchargées à l’étape 1.0)
Action 1.3 – Remplaçons le contenu du fichier ‘ViewController.swift’ par;
// // ViewController.swift // Les amis de la science // // Créé par Alain Boudreault le 2014-09-28. // Copyright (c) 2014-2016 Alain. All rights reserved. // ------------------------------------------------------------------ // m-a-j: 2016.08.23 - conversion du projet vers Xcode 8 et swift 3 // 2016.10.16 - fin de la conversion vers swift 3 // 2017.10.15 - conversion vers Xcode 9 et swift 4 // ------------------------------------------------------------------ import UIKit class ViewController: UIViewController { // ou bien: Array<Dictionary<String,String>> let lesAmisDeLaScienceData:[Dictionary<String,String>] = [ ["nom":"Albert Einstein", "photo":"Albert Einstein.jpg", "texte":"lorem ipsum01 ...", "naissance":"1900"], ["nom":"Albert Jacquard", "photo":"Albert Jacquard.jpg", "texte":"lorem ipsum02 ...", "naissance":"1900"], ["nom":"Blaise Pascal", "photo":"Blaise Pascal.jpg", "texte":"lorem ipsum03 ...", "naissance":"1900"], ["nom":"Braun", "photo":"Braun.jpg", "texte":"lorem ipsum04 ...", "naissance":"1900"], ["nom":"Christian Huygens", "photo":"Christian Huygens.jpg", "texte":"lorem ipsum05 ...", "naissance":"1900"], ["nom":"Daniel Fahrenheit", "photo":"Daniel Fahrenheit.jpg", "texte":"lorem ipsum06 ...", "naissance":"1900"], ["nom":"Dennis Ritchie", "photo":"Dennis Ritchie.jpg", "texte":"lorem ipsum07 ...", "naissance":"1900"], ["nom":"Galileo Galilei", "photo":"Galilée.jpg", "texte":"lorem ipsum08 ...", "naissance":"1900"], ["nom":"Henri Becquerel", "photo":"Henri Becquerel.jpg", "texte":"lorem ipsum09 ...", "naissance":"1900"], ["nom":"Heinrich Hertz", "photo":"Hertz.jpg", "texte":"lorem ipsum10 ...", "naissance":"1900"], ["nom":"Jean Perrin", "photo":"Jean Perrin.jpg", "texte":"lorem ipsum11 ...", "naissance":"1900"], ["nom":"Karl Guthe Jansky", "photo":"Karl Guthe Jansky.jpg", "texte":"lorem ipsum12 ...", "naissance":"1900"], ["nom":"Marie Curie", "photo":"Marie Curie.jpg", "texte":"lorem ipsum13 ...", "naissance":"1900"], ["nom":"James Clerk Maxwell", "photo":"maxwell.jpg", "texte":"lorem ipsum14 ...", "naissance":"1900"], ["nom":"Steve Jobs", "photo":"Steve Jobs.jpg", "texte":"lorem ipsum15 ...", "naissance":"1900"], ["nom":"Wilhelm Conrad Rontgen","photo":"Wilhelm Conrad Rontgen.jpg", "texte":"lorem ipsum16 ...", "naissance":"1900"], ] // lesAmisDeLaScienceData // ***************************************************** override func viewDidLoad() // ***************************************************** { super.viewDidLoad() if let nomFichierImage = lesAmisDeLaScienceData[0]["photo"] { let uneImage = UIImageView(image: UIImage(named: nomFichierImage)) view.addSubview(uneImage) } // if let } // viewDidLoad } // ViewController
Action 1.4 – Testons l’application dans le simulateur.
Action 1.5 – Analysons le code; le tableau de dictionnaires et l’image chargée par programmation.
Note: Par inférence, le tableau est signé [Dictionary <String, String>]. Cela représente le mode d’utilisation le plus simple qui soit. Il ne sera pas nécessaire de signer les accès. Par exemple, comme ceci:
(lesAmisDeLaScienceData[2] as Dictionary<String, AnyObject>)[« nom »] as String
Action 1.6 – Glissons un UITableView sur la scène
Action 1.7 – Observons les protocoles disponibles pour l’objet UITableView .
Action 1.8 – Souscrivons, le contrôleur de la scène, au protocole ‘dataSource’ du UITableView.
Action 1.9 – Ajoutons le nom du protocole à la suite de la définition de la classe du contrôleur de la scène.
Note: Cette opération est redonnante avec 1.8. Elle permet d’indiquer à Xcode de nous afficher les méthodes du protocole lorsqu’en mode ‘complétion de code’.
class ViewController: UIViewController, UITableViewDataSource { // Note: Cette ligne sera en erreur tant que les méthodes obligatoires du // protocole dataSource ne seront pas déclarées dans la classe du contrôleur. }
Action 1.10 – Mettons en commentaire les lignes suivantes de la méthode ‘viewDidLoad’.
// ***************************************************** override func viewDidLoad() // ***************************************************** { super.viewDidLoad() //let uneImage = UIImageView(image: UIImage(named: lesAmisDeLaScienceData[0]["photo"]!)) //view.addSubview(uneImage) } // viewDidLoad
Lorsqu’une de nos classes adopte le protocole ‘dataSource’ de la classe ‘UITableView‘ nous avons l’obligation de programmer les deux méthodes suivantes:
La méthode ‘tableView – numberOfRowsInSection’ sert à indiquer au ‘TableView’ le nombre de lignes (enregistrements) à afficher. Habituellement, cette méthode retourne le nombre d’éléments du tableau des données.
La méthode ‘tableView – cellForRowAtIndexPath’ sert à fournir les données à utiliser pour faire le rendu de la cellule courante. Cette méthode est appelé automatiquement à chaque fois qu’une cellule doit être affichée à l’écran ou suite à l’utilisation de la méthode UITableView.reloadData().
Action 1.11 – Ajoutons les méthodes obligatoires du protocole dataSource à la classe de la scène principale:
tableView->numberOfRowsInSection et tableView->cellForRowAt indexPath
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return lesAmisDeLaScienceData.count } // numberOfRowsInSection func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { print("#Construction de la cellule numéro: \(indexPath.row)") return UITableViewCell() } // cellForRowAt
Action 1.12 – Testons l’application.
Note: Le TableView affiche ‘lesAmisDeLaScience.count’ cellules vides.
Action 1.13 – Ajoutons le code suivant à la méthode ‘tableView – cellForRowAtIndexPath’.
// test 1 // ---------------------------------------------------------------------- func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { print("#Construction de la cellule numéro: \(indexPath.row)") let uneCellule = UITableViewCell() uneCellule.textLabel!.text = "Ceci est la description no \(indexPath.row)" return uneCellule } // cellForRowAt indexPath // ---------------------------------------------------------------------- // test 2 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { print("#Construction de la cellule numéro: \(indexPath.row)") let uneCellule = UITableViewCell() var nomDuScientifique = "n/a" if let _nom = lesAmisDeLaScienceData[indexPath.row]["nom"] { nomDuScientifique = _nom } uneCellule.textLabel!.text = nomDuScientifique return uneCellule } // cellForRowAt indexPath
Action 1.14 – Testons l’application.
Action 1.15 – Ajoutons le code suivant à la méthode ‘tableView – cellForRowAtIndexPath’.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { print("#Construction de la cellule numéro: \(indexPath.row)") let uneCellule = UITableViewCell() var nomDuScientifique = "n/a" if let _nom = lesAmisDeLaScienceData[indexPath.row]["nom"] { nomDuScientifique = _nom } uneCellule.textLabel!.text = nomDuScientifique if let fichierImage = lesAmisDeLaScienceData[indexPath.row]["photo"] { uneCellule.imageView!.image = UIImage(named:fichierImage) } return uneCellule } // cellForRowAt indexPath
Action 1.16 – Testons l’application.
Note: Si le défilement ne fonctionne pas correctement, ajustez les contraintes de mise en page du UITableView:
Action 1.17 – Ajoutons un objet ‘UITableViewCell‘ au tableView de la scène.
Pour avoir accès aux éléments que nous placerons dans la cellule, il faut y associer une classe perso.
Action 1.18 – Ajoutons une nouvelle classe au projet. Cette classe doit étendre la classe ‘UITableViewCell’.
Action 1.19 – Associons la classe « Savant » à la nouvelle cellule.
Action 1.19.2 – Renseignons la propriété ‘Identifier’ de la cellule avec la chaine « celluleSavant ». Cela représente une référence au design de la cellule.
Action 1.20 – Plaçons les éléments de design dans la cellule et définissons des liens MCV.
Attention, assurons nous que l’assistant éditeur affiche le contenu du fichier Savant.swift.
@IBOutlet weak var savantNom: UILabel! @IBOutlet weak var savantImage: UIImageView! @IBOutlet weak var savantTexte: UITextView! @IBOutlet weak var savantAge: UILabel!
Action 1.21 – Ajoutons le code suivant à la méthode ‘tableView – cellForRowAtIndexPath’.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { print("#Construction de la cellule numéro: \(indexPath.row)") var uneCellule:Savant uneCellule = tableView.dequeueReusableCell(withIdentifier: "celluleSavant") as! Savant var nomDuScientifique = "n/a" if let _nom = lesAmisDeLaScienceData[indexPath.row]["nom"] { nomDuScientifique = _nom } uneCellule.savantNom.text = nomDuScientifique if let fichierImage = lesAmisDeLaScienceData[indexPath.row]["photo"] { uneCellule.savantImage.image = UIImage(named:fichierImage) } // En déballage forcé: uneCellule.savantTexte.text = lesAmisDeLaScienceData[indexPath.row]["texte"] return uneCellule } // cellForRowAt indexPath
Action 1.22 – Terminons le design de la cellule.
Note: À partir de Xcode 9, le UITableView va tenter d’ajuster la hauteur des cellules automatiquement. Cela peut produire un résultat indésirable.
Il est possible de désactiver ce comportement dans l’inspecteur de taille du UITableView en décochant la propriété ‘Row Height Automatic’
À cette étape, nous remplacerons le tableau codé en dur par un tableau créé à partir d’un fichier de données livré avec l’application.
Action 2.2 Observons la structure du fichier ‘amisDelaScience.plist’. Voir dans le groupe Ressources.Données
Action –
Action 2.3 – Affichons la source du fichier de données (Ctrl+Clic):
Résultat:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <array> <dict> <key>nom</key> <string>Albert Einstein</string> <key>photo</key> <string>Albert Einstein.jpg</string> <key>texte</key> <string>Il publie sa theorie de la relativite restreinte en 1905, et une theorie de la gravitation dite relativite generale en 1915.</string> <key>naissance</key> <string>1879</string> </dict> <dict> <key>nom</key> <string>Albert Jacquard</string> <key>photo</key> <string>Albert Jacquard.jpg</string> <key>texte</key> <string>Il est connu pour ses engagements citoyens, parmi lesquels la defense du concept de la decroissance soutenable, le soutien aux mouvements du logiciel libre, a la langue internationale esperanto, aux laisses-pour-compte et a l'environnement.</string> <key>naissance</key> <string>1925</string> </dict> ... </array> </plist>
Action 2.4 – Dans le fichier ‘ViewController.swift’, remplaçons la définition (codée au dur) du tableau des amis de la science par:
// Définition d'un tableau de dictionnaires // Le dictionnaire est 'typé' clé = String et contenu = String dans le but d'alléger // la syntaxe d'accès aux éléments du dictionnaire. var lesAmisDeLaScienceData:Array<Dictionary<String,String>> = []
La classe NSArray – du Foundation framework – propose un méthode qui permet de créer un tableau à partir d’un fichier de propriétés:
Action 2.5 – Ajoutons le code suivant à la méthode viewDidLoad.
override func viewDidLoad() { super.viewDidLoad() let pathFichierPlist = Bundle.main.path(forResource: "amisDelaScience", ofType: "plist")! print("#pathFichierPlist: \(pathFichierPlist)") // Voir documentation pour Array VS NSArray: // https://developer.apple.com/reference/swift/array // https://developer.apple.com/reference/foundation/nsarray lesAmisDeLaScienceData = NSArray(contentsOfFile: pathFichierPlist) as! Array } // viewDidLoad
Note: Remarquez, dans la console, la complexité du chemin d’accès vers le fichier ‘amisDelaScience.plist.
Action 2.6 – Testons notre modification
Action 2.7 – Calculons l’age du savant avec le code suivant.
// func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { // Recette pour obtenir la valeur de l'année courante let date = Date() let calendar = NSCalendar.current let components = calendar.dateComponents([.year], from: date) let anneeCourante = components.year let anneeNaissance = lesAmisDeLaScienceData[(indexPath as NSIndexPath).row]["naissance"]! print("# \(anneeCourante), \(anneeNaissance)\n") uneCellule.savantAge.text = "\(anneeCourante! - Int(anneeNaissance)!) ans"
Action 2.8 – Testons l’application.
La classe UICollectionView permet l’affichage d’une liste d’éléments sur plusieurs colonnes.
Mise à part le fait qu’un UICollectionView ne propose pas une cellule avec des champs par défaut, c-a-d qui faudra utiliser une classe perso pour la cellule, cet objet se programme presque de la même façon qu’un UITableView.
Nous allons reprendre l’exercice de l’étape 2 en utilisant un UICollectionView.
Action 3.1 – Ouvrir le storyboard du module 03. Effaçons le UICollectionView.
Action 3.2 – Glissons un objet ‘CollectionView‘, de la librairie vers la scène.
Note: Remarquez qu’il y a déjà une cellule à personnaliser dans le UICollectionView.
Action 3.3 – Ajustons la taille et la couleur de fond – clear color – du collectionView ainsi que la taille de la cellule.
Action 3.4 – Élaborons le design de la nouvelle cellule en y ajoutant un ‘UILabel’ pour le nom, une image et une zone de texte au bas.
Action 3.5 – Souscrivons le contrôleur de la scène au protocole ‘dataSource‘ du UICollectionView.
Note: Expliquer l’opération par programmation:
@IBOutlet weak var CVSavant: UICollectionView! ... viewDidLoad(){ CVSavant.dataSource = self
Action 3.6 – Ajoutons le nom du protocole à la suite de la définition de la classe du contrôleur de la scène.
Note: Cette opération est redonnante avec 3.5. Elle permet d’indiquer à Xcode de nous afficher les méthodes du protocole lorsqu’en mode ‘complétion de code’.
class ViewController: UIViewController, UICollectionViewDataSource { // Note: Cette ligne sera en erreur tant que les méthodes obligatoires du // protocole ne seront pas déclarées dans la classe du contrôleur.
Action 3.7 – Ajoutons les méthodes ‘collectionView: numberOfItemsInSection’ et ‘collectionView: cellForItemAtIndexPath’ à la classe de la scène principale.
Action 3.8 – Ajoutons le code suivant aux nouvelles méthodes.
//MARK:- Méthodes du protocole UICollectionViewDataSource func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return lesAmisDeLaScienceData.count } // numberOfItemsInSection func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { return UICollectionViewCell() // Va faire planter l'application! } // cellForItemAt indexPath
Action 3.9 – Testons l’app.
Note: Il y aura une erreur à l’exécution.
2014-09-30 12:51:08.025 Les amis de la science[36210:2367199] *** Assertion failure in -[UICollectionView _createPreparedCellForItemAtIndexPath:withLayoutAttributes:applyAttributes:],/SourceCache/UIKit_Sim/UIKit-3318/UICollectionView.m:1315
2014-09-30 12:51:08.028 Les amis de la science[36210:2367199] *** Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘the cell returned from -collectionView:cellForItemAtIndexPath: does not have a reuseIdentifier – cells must be retrieved by calling -dequeueReusableCellWithReuseIdentifier:forIndexPath:’
Explication – Il faut absolument recycler les cellules avec un UICollectionView: dequeueReusableCellWithReuseIdentifier.
Il faudra donc;
Action 3.10 – Ajoutons une classe, dérivée de UICollectionViewCell, pour la cellule.
Action 3.11 – Renseignons la propriété ‘Class’ de la cellule.
Action 3.12 – Renseignons la propriété ‘Identifier’ de la cellule avec la chaine suivante: « modeleCelluleSavant ».
Action 3.13 – Ajoutons le code suivant à la méthode ‘collectionView: cellForItemAtIndexPath‘.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { var celluleCourante:CVCSavant celluleCourante = collectionView.dequeueReusableCell(withReuseIdentifier: "modeleCelluleSavant", for:indexPath) as! CVCSavant return celluleCourante } // cellForItemAt indexPath
Action 3.14 – Testons l’application.
Note: Le modèle est maintenant utilisée pour le rendu des cellules.
Action 3.15 – Ajoutons les déclarations MVC suivantes au fichier ‘CVCSavant.swift’
// CVCSavant.swift import UIKit class CVCSavant: UICollectionViewCell { @IBOutlet weak var savantNom: UILabel! @IBOutlet weak var savantImage: UIImageView! @IBOutlet weak var savantTexte: UITextView! } // class CVCSavant
Action 3.16 – Associons les déclarations aux objets dans la cellule.
Action 3.17 – Ajoutons le code suivant à la méthode ‘collectionView: cellForItemAtIndexPath‘.
// func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { // ... // Renseigner les élements de la cellule courante // Recette pour obtenir la valeur de l'année courante let date = Date() let calendar = NSCalendar.current let components = calendar.dateComponents([.year], from: date) let anneeCourante = components.year let anneeNaissance = lesAmisDeLaScienceData[(indexPath as NSIndexPath).row]["naissance"]! let age = " - \(anneeCourante! - Int(anneeNaissance)!) ans" celluleCourante.savantNom.text = lesAmisDeLaScienceData[indexPath.row]["nom"]! + age celluleCourante.savantTexte.text = lesAmisDeLaScienceData[(indexPath as NSIndexPath).row]["texte"]! celluleCourante.savantImage.image = UIImage(named: lesAmisDeLaScienceData[(indexPath as NSIndexPath).row]["photo"]!) // return celluleCourante // } // collectionView: cellForItemAtIndexPath
Action 3.18 – Testons l’application.
Action 3.19 – À vous d’ajuster le design.
Il est possible d’utiliser plusieurs modèles de rendu pour les cellules personnalisées de UITableView et UICollectionView.
Action 3.20.a – Copions – atl+glisser – la cellule du UICollectionVue.
Attention, assurez-vous que la cellule est bien sélectionnée. Au besoin, utilisez l’explorateur de document.
Action 3.20.b – Corrigeons la propriété ‘Identifier’ de la nouvelle cellule pour ‘modeleCelluleSavant2’.
Note: Il n’est pas nécessaire de renseigner la propriété ‘class’, la nouvelle cellule possède toutes les propriétés de la première.
Action 3.21 – Modifions le design du nouveau modèle.
Action 3.22 – Modifions le code suivant.
// func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { // Recyclage obligatoire pour un UICollectionViewCell let nomModele = indexPath.row % 2 == 0 ? "modeleCelluleSavant":"modeleCelluleSavant2" celluleCourante = collectionView.dequeueReusableCell(withReuseIdentifier: nomModele, for:indexPath) as! CVCSavant
Action 3.23 – Testons l’application.
À cette étape nous allons programmer, suite à la sélection d’une cellule par l’utilisateur, un déplacement – segue – vers une scène affichant les informations de la sélection courante.
Action 4. – Ajoutons et élaborons une scène, pour les informations du savant,
Action 4.2 – Ajoutons une nouvelle classe au projet pour la scène ‘Détails’ nommée ‘VCDetails’
Action 4.3 – Associons la classe ‘VCDetails’ à la scène ‘Détails’.
Action 4.4 – Définissons un @IBAction entre le bouton de retour en arrière et la classe de la scène ‘Détails’.
Action 4.5 – Ajoutons, à la méthode ‘retourALaListe’ le code suivant:
dismiss(animated: true, completion: nil)
Pour définir un segue entre une cellule d’un tableView ou d’un CollectionView, il suffit de ‘Ctrl+Glisser’ la cellule vers la View de la scène de destination.
Note: S’il y a plusieurs cellules, il faut alors recommencer cette opération pour toutes les cellules restantes.
Action 4.6 – Définissons un segue de type ‘present modally’, à partir de la première cellule, vers la scène ‘Détails’.
Action 4.7 – Recommençons la manœuvre sur la deuxième cellule.
Action 4.8 – Observons le résultat obtenu.
Action 4.9 – Testons l’application.
La classe UIViewController propose la méthode ‘prepareForSegue’ comme moyen de passer des informations à la scène de destination lors d’un segue.
Celle méthode est programmée dans le contrôleur de la scène de départ; celle qui présente le TableView ou le CollectionView.
Voici sa signature:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
La méthode reçoit (lors de l’appel) une référence vers la destination ainsi qu’une référence sur l’objet – habituellement une cellule – ayant reçu l’événement déclencheur du segue.
Action 4.10 – Ajoutons le code suivant au contrôleur de la scène principale:
// Méthode exécutée automatiquement avant un segue //MARK:- Préparer le déplacement (segue) override func prepare(for segue: UIStoryboardSegue, sender: Any?) { print("# Exécution de la méthode: prepare:for segue\n") } // prepare(for segue: ...)
Action 4.11 – Testons l’application (faire plusieurs sélections).
Action 4.12 – Définissons un @IBOutlet sur le collectionView.
Les classes UITableView et UICollectionView proposent la méthode ‘indexPathForCell(uneCellule)’ pour connaitre la position d’une cellule.
Lors de l’exécution de la méthode ‘prepareForSegue’, nous recevons une référence (sender: Any?) à la cellule sélectionnée.
Par conséquent, le code suivant permet de connaitre l’indice de la cellule sélectionnée:
Action 4.13 – Ajoutons le code suivant à la méthode ‘prepareForSegue‘.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { // Note: Il faut avoir renseigné un @IBOutlet sur le UICollectionView let selection = CVSavant.indexPath(for: sender as! UICollectionViewCell)!.row print("# Exécution de la méthode: prepareForSegue pour la cellule numéro: \(selection)\n") } // prepare(for segue: ...)
Action 4.14 – Testons l’application.
Il nous reste maintenant à passer les informations de la sélection courante à la scène de détails.
La méthode ‘prepareForSegue‘ nous renseigne aussi sur la destination: (segue: UIStoryboardSegue).
segue.destinationViewController -> pointe sur l’instance de classe du contrôleur de la scène de destination.
Donc, avec le code suivant, nous aurons accès aux propriétés publiques du contrôleur de la scène de destination:
var destination = segue.destinationViewController as VCDetails
destination.uneVariable = …
Action 4.15 – Ajoutons le code suivant au contrôleur VCDetails.
class VCDetails: UIViewController { // Propriété pour recevoir les informations de la sélection var informationsDuSavantCourant = Dictionary<String,String> () override func viewDidLoad() { super.viewDidLoad() print("# Nous avons reçu les données suivantes:\(informationsDuSavantCourant)\n") } // viewDidLoad
Action 4.16 – Ajoutons le code suivant à la méthode prepareForSegue de ViewController.swift.
//MARK:- Préparer le déplacement (segue) override func prepare(for segue: UIStoryboardSegue, sender: Any?) { // Note: Il faut avoir renseigné un @IBOutlet sur le UICollectionView // 1 - Déterminer l'index de la sélection à partir de la cellule reçue en paramètre (sender) let selection = CVSavant.indexPath(for: sender as! UICollectionViewCell)!.row yo(dans: String(selection)) print("# Exécution de la méthode: prepareForSegue pour la cellule numéro: \(selection)\n") // 2 - Créer un objet pointant sur l'instance de classe de la destination let destination = segue.destination as! VCDetails // 3 - Passer les informations au controleur de destination destination.informationsDuSavantCourant = lesAmisDeLaScienceData[selection] } // prepare(for segue: ...)
Action 4.17 – Testons l’application.
Action 4.18 – En faire en laboratoire: Vous devez définir des IBOutlet sur les objets de la scène ‘Détails’ et afficher, sur la scène, les informations reçues.
Résultat:
Et si le fichier de données provenait du monde exterieur?
Par exemple, au bout d’un URL comme, http://prof-tim.cstj.qc.ca/cours/xcode/sources/amisDelaScience.plist
Action 5.1 – Ajoutons le code suivant à la méthode ‘viewDidLoad’:
let strURL = "http://prof-tim.cstj.qc.ca/cours/xcode/sources/amisDelaScience.plist" if let uneURL = URL(string: strURL) { if let _données = NSArray(contentsOf: uneURL) as? Array<Dictionary<String, String>> { lesAmisDeLaScienceData = _données print(_données) } else { print("\n\n#Erreur: impossible de créer un tableau à partir du fichier... \(strURL)\n\n") } // Problème avec l'URL } else { print("\n\n#Erreur: impossible de lire les données via \(strURL)\n\n") }
Note: Depuis iOS 10, la sécurité a été augmenté.
Il faut permettre les connexions arbitraires de l’application:
Action 5.2 – . Ajoutons la clé suivante dans le fichier info.plist
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Fin du document