NEW: Join my free 100 Days of SwiftUI challenge today! >>

Chargement des images avec UIImage

À ce stade, nous avons notre Table View Controller d'origine rempli d'images à sélectionner, ainsi qu'un Detail View Controller dans notre storyboard. L’étape suivante consiste à afficher l’écran du Detail View Controller lorsqu'une ligne du tableau est tapée, et afficher l’image sélectionnée.

Pour que cela fonctionne, nous devons ajouter une autre méthode portant un nom particulier à ViewController. Celle-ci s'appelle tableView(_, didSelectRowAt:), qui prend une valeur IndexPath comme pour cellForRowAt, qui indique la ligne avec laquelle nous travaillons. Cette fois, nous avons un peu plus de travail à faire :

  1. Nous devons créer une propriété dans DetailViewController qui contiendra le nom de l'image à charger.
  2. Nous allons implémenter la méthode didSelectRowAt afin qu’elle charge un DetailViewController à partir du storyboard.
  3. Enfin, nous allons compléter la méthode viewDidLoad() dans DetailViewController afin qu’elle charge une image dans l'élément Image View qu'elle contient, en fonction du nom que nous avons défini précédemment.

Nous allons résoudre chacun de ces problèmes dans l’ordre, en commençant par le premier : créer une propriété dans DetailViewController qui contiendra le nom de l’image à charger.

Cette propriété sera de type chaîne de caractère - le nom de l’image à charger - mais de type optionnel car, lorsque le contrôleur de vue est crée, elle n’existe pas encore. Nous allons la déclarer tout de suite, mais elle commencera sa vie sans valeur (nil).

Donc, ajoutez maintenant cette propriété à DetailViewController, juste en-dessous de la ligne @IBOutlet existante :

var selectedImage: String?

Ça y est, la première tâche est accomplie. Passons donc à la deuxième : implémenter didSelectRowAt pour qu’elle charge un DetailViewController à partir du storyboard.

Lorsque nous avons créé Detail View Controller, vous lui avez attribué l'ID de storyboard "Detail", ce qui nous permet de le charger à partir du storyboard à l'aide d'une méthode appelée instantiateViewController(withIdentifier:). Chaque contrôleur de vue a une propriété appelée storyboard qui correspond au storyboard à partir duquel elle a été chargée ou à nil. Dans le cas de ViewController, il s'agira de Main.storyboard, qui est le même storyboard que celui qui contient Detail View Controller. Nous allons donc charger DetailViewController à partir de là.

Nous pouvons diviser cette tâche en trois tâches plus petites, dont deux sont nouvelles :

  1. Charger la mise en page de Detail View Controller à partir de notre storyboard.
  2. Définir sa propriété selectedImage sur l'élément correct du tableau pictures.
  3. Afficher le nouveau contrôleur de vue.

La première de celles-ci est accomplie en appelant instantiateViewController, mais elle comporte deux petites complexités. Premièrement, nous l’appelons dans la propriété storyboard que nous obtenons à partir du type UIViewController d’Apple, mais elle est optionnelle, car Swift ne sait pas que nous venons d’un storyboard. Nous devons donc utiliser ? comme lorsque nous avons défini la propriété textLabel de notre cellule : "essaye de faire cela, mais ne fais rien s'il y a un problème".

La deuxième, même si instantiateViewController() nous retournera un DetailViewController si tout a correctement fonctionné, Swift pense qu'il retournera un UIViewController car il ne peut pas voir ce qui se passe dans le storyboard.

Cela va vous sembler déroutant si vous débutez en programmation, alors laissez-moi essayer de l’expliquer par une analogie. Disons que vous voulez sortir avec quelqu'un ce soir, alors demandez-moi de vous procurer quelques billets pour un événement. Je pars, trouve des billets, puis vous les remets dans une enveloppe. J'ai rempli ma part du marché : vous avez demandé des billets, je vous ai eu des billets. Mais de quels billets s'agit-il - des billets pour un événement sportif ? Des billets pour un opéra ? Des billets de train ? La seule façon pour vous de le savoir est d'ouvrir l'enveloppe et de regarder.

Swift a le même problème: instantiateViewController() retourne un type UIViewController, ainsi, pour Swift, tout contrôleur de vue créé est de type UIViewController. Cela nous pose un problème parce que nous voulons donner une valeur à la propriété que nous venons de créer dans DetailViewController. La solution : nous devons dire à Swift que ce qu’il a n’est pas ce qu’il pense.

Le terme technique utilisé pour ceci est "typecasting" (conversion de type)': demander à Swift de traiter une valeur comme un type différent. Swift a plusieurs façons de le faire, mais nous allons utiliser la version la plus sûre : ce qui signifie effectivement "s'il te plaît, essaye de traiter ceci comme un DetailViewController, mais si cela échoue, ne fais rien et continue".

Une fois que nous avons un Detail View Controller dans les mains, nous pouvons définir sa propriété selectedImage pour qu'elle soit égale à pictures[indexPath.row], comme nous l'avons fait dans cellForRowAt - c’est la partie facile.

La troisième mini-étape consiste à afficher le nouvel écran. Vous avez déjà vu que les contrôleurs de vue ont une propriété optionnelle storyboard qui contient le storyboard à partir duquel ils ont été chargés ou nil. Eh bien, ils ont aussi une propriété optionnelle navigationController qui contient le contrôleur de navigation dans lequel ils se trouvent s’il existe, ou sinon nil.

C'est parfait pour nous, car les contrôleurs de navigation ont la responsabilité d'affichager des écrans. Bien sûr, ils fournissent cette jolie barre grise en haut que vous voyez dans de nombreuses applications, mais ils sont également responsables de la gestion du grand nombre d'écrans dans lesquels les utilisateurs naviguent.

Par défaut, ils contiennent le premier contrôleur de vue que vous avez créé pour eux dans le storyboard, mais lorsque de nouveaux écrans sont créés, vous pouvez les placer dans la pile du contrôleur de navigation pour les faire glisser sans problèmes, comme vous le voyez dans Réglages. Au fur et à mesure que de nouveaux écrans sont placés dans la pile, ils continuent à glisser. Lorsque les utilisateurs reviennent en arrière, c’est-à-dire en touchant Précédent ou en balayant de gauche à droite, le contrôleur de navigation détruit automatiquement l’ancien contrôleur de vue et libère sa mémoire.

Ces trois mini-étapes complètent la nouvelle méthode, il est donc temps de coder. Veuillez ajouter cette méthode à ViewController.swift. J'ai ajouté des commentaires pour faciliter la compréhension :

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    // 1: try loading the "Detail" view controller and typecasting it to be DetailViewController
    if let vc = storyboard?.instantiateViewController(withIdentifier: "Detail") as? DetailViewController {
        // 2: success! Set its selectedImage property
        vc.selectedImage = pictures[indexPath.row]

        // 3: now push it onto the navigation controller
        navigationController?.pushViewController(vc, animated: true)
    }
}

Examinons un peu plus attentivement la ligne if let. Il y a trois parties qui pourraient échouer : la propriété storyboard pourrait être nil (dans ce cas, le ? arrêtera l'exécution du reste de la ligne), l'appel à instantiateViewController() pourrait échouer si nous avions demandé "Fzzzzz" ou un autre ID de storyboard non valide, ainsi que la conversion de type - la partie as?, car nous aurions pu recevoir un contrôleur de vue d'un type différent.

Ainsi, trois éléments de cette ligne risquent d’échouer. Si vous avez suivi toutes mes étapes correctement, ils n'échoueront pas, mais ils ont le potentiel d'échouer. C’est là que if let est intelligent : si l’un de ces éléments ne retourne rien (c’est-à-dire qu’ils échouent), le code à l’intérieur des accolades if let ne sera pas exécuté. Cela garantit que votre programme est dans un état sûr avant d'effectuer toute action.

Avant de pouvoir examiner les résultats, il ne vous reste plus qu’une petite chose à effectuer : nous devons faire en sorte que l’image soit en fait chargée dans l'élément Image View dans DetailViewController.

Ce nouveau code utilisera un nouveau type de données, appelé UIImage. Contrairement à UIImageView, son nom n'a pas le "View". Ce n’est donc pas quelque chose que vous pouvez voir - ce n’est pas quelque chose qui est en fait visible pour les utilisateurs. UIImage est le type de données que vous utiliserez pour charger des données de type image, telles que les fichiers PNG ou JPEG.

Lorsque vous créez un UIImage, il prend un paramètre appelé named qui vous permet de spécifier le nom de l'image à charger. UIImage recherche ensuite ce nom de fichier dans le bundle de votre application et le charge. En le passant ici dans la propriété selectedImage, qui a été envoyée à partir de ViewController, cela chargera l'image sélectionnée par l'utilisateur.

Cependant, nous ne pouvons pas utiliser selectedImage directement. Si vous vous en souvenez, nous l'avons créé comme ceci:

var selectedImage: String?

Ce ? là signifie que cette propriété peut avoir une valeur ou non, et Swift ne vous permet pas d’utiliser ces "peut-être" sans les vérifier au préalable. C'est une autre opportunité d'utiliser if let : nous pouvons vérifier que selectedImage a une valeur, et si c'est le cas, l'extraire pour l'utiliser ; sinon, ne rien faire.

Ajoutez ce code à viewDidLoad() dans DetailViewController, après l'appel à super.viewDidLoad() :

if let imageToLoad = selectedImage {
    imageView.image  = UIImage(named: imageToLoad)
}

La première ligne permet de vérifier et de déballer l’optionnel selectedImage. Si, pour une raison quelconque, selectedImage est nil (ce qui ne devrait jamais être le cas en théorie), la ligne imageView.image ne sera jamais exécutée. S'il a une valeur, il sera placé dans imageToLoad, puis passé à UIImage et chargé.

OK, c’est tout : appuyez maintenant sur play ou sur Cmd + R pour exécuter l’application et l’essayer ! Vous devriez pouvoir sélectionner n'importe quelle image pour la faire glisser et l'afficher en plein écran.

Notez que nous avons un bouton Back dans la barre de navigation qui nous permet de revenir à ViewController. Vous constaterez que vous pouvez également utiliser un geste de balayage : touchez le bord gauche de l'écran, puis faites glisser vers la droite, comme vous le feriez avec votre pouce sur un téléphone.

LEARN SWIFTUI FOR FREE I have a massive, free SwiftUI video collection on YouTube teaching you how to build complete apps with SwiftUI – check it out!

MASTER SWIFT NOW
Buy Testing Swift Buy Practical iOS 12 Buy Pro Swift Buy Swift Design Patterns Buy Swift Coding Challenges Buy Server-Side Swift (Vapor Edition) Buy Server-Side Swift (Kitura Edition) Buy Hacking with macOS Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with Swift Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!