SALE ENDS TODAY: Save 50% on all Swift books and bundles! >>

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.

SPONSORED Instabug helps you identify and resolve severe crashes quickly. You can retrace in-app events and know exactly which line of code caused the crash along with environment details, network logs, repro steps, and the session profiler. Ask more questions or keep users up-to-date with in-app replies straight from your dashboard. Instabug takes data privacy seriously, so no one sees your data but you! See more detailed features comparison and try Instabug's crash reporting SDK for free.

Save 50% on all books and bundles

The biggest ever Hacking with Swift sale is now on, letting you save 50% on all books and bundles. Learn something new with Swift and enjoy great savings while the sale lasts!

Click here to save 50% in our Black Friday sale!

BUY OUR BOOKS
Buy Pro Swift Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift (Vapor Edition) Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Server-Side Swift (Kitura Edition) Buy Beyond Code

Was this page useful? Let us know!