• 15 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 1/6/21

Analysez la pile après un plantage

Je vous propose maintenant de regarder un peu le projet Xcode de l'application Jeu Set & Match que vous venez de télécharger.

Une fois le projet ouvert, notre premier réflexe est bien sûr de lancer l'application pour la prendre en main et bien comprendre son fonctionnement. Alors, allons-y !

Mais... Mais... L'application a planté !

Ah la boulette... Toutes mes excuses, je pensais pourtant vous avoir concocté un projet tout beau tout propre ! Comme quoi, ça arrive même aux meilleurs ;) !

Bon ne nous démontons pas, on va essayer de comprendre et détecter cette erreur. Pour cela, voyons ce que Xcode nous raconte dans la console :

La sortie console qui contient l'erreur

Ouh là, on dirait qu'Xcode est bavard ! Pas de panique, je vais vous expliquer tout ça !

La pile d'exécution

La longue liste que vous affiche Xcode en cas d'erreur, c'est la pile d'exécution (ou call stack en anglais).

Quésaco ?

Une pile d'exécution permet de mémoriser l'enchaînement d'appels des méthodes (ou fonctions) d'un programme. Pour ce faire, une structure de données de type pile est utilisée. Ce mécanisme permet de garder une trace des fonctions appelées, afin de pouvoir "revenir sur ses pas" lorsqu'une fonction est terminée.

Prenons un petit exemple pour illustrer cela :

  • Imaginez que vous ayez une fonction nommée getTemperature qui vous renvoie la température extérieure.

  • Cette fonction utilise une autre fonction getTemperatureFromSensor, qui permet d'interroger le thermomètre.

  • Enfin, la fonction getTemperatureFromSensor utilise une dernière fonction nommée convertFahrenheitToCelsius qui convertit en degrés Celsius une température initialement en degrés Fahrenheit.

Le code simplifié correspondant serait :

func  getTemperature() -> Int {
  return getTemperatureFromSensor()
}

func getTemperatureFromSensor() -> Int {
  let fahrenheitTemperature = sensor.getTemperature()
  return convertFarenheitToCelsius(farenheit:  farenheitTemperature)
}

func convertFahrenheitToCelsius(fahrenheit: Int) -> Int{
  return (fahrenheit - 32) * 5 / 9;
}

Lorsque vous appelez la fonction getTemperature, elle est automatiquement ajoutée à la pile. La pile contient donc :

Pile

getTemperature

Ensuite, au sein de la fonction getTemperature, c'est au tour de la fonction getTemperatureFromSensor d'être appelée. Elle est également ajoutée à la pile. La pile contient donc :

Pile

getTemperatureFromSensor

getTemperature

Enfin, c'est au tour de la fonction convertFahrenheitToCelsius d'être appelée. Après avoir été ajoutée à la pile, cette dernière contient donc :

Pile 

convertFahrenheitToCelsius

getTemperatureFromSensor

getTemperature

À la fin de l'exécution d'une fonction, elle est "dépilée", c'est-à-dire qu'elle est retirée de la pile. On revient à la fonction appelante. Par exemple, quand convertFahrenheitToCelsius a terminé son exécution, elle est retirée de la pile et on retourne à getTemperatureFromSensor qui peut reprendre le cours de son exécution.

Analyse de la pile

Regardons maintenant notre pile. Elle contient 48 appels des couches les plus basses de notre programme aux couches les plus élevées. Dans l'analyse, l'objectif est de retrouver les lignes qui correspondent à notre code, le reste ne nous intéresse pas a priori.

Image de la pile dans la console avec mise en évidence de ses différentes parties.

Ici, en vert, vous pouvez trouver la pile d'appels de fonctions dans le ViewController. La voici en détail :

| Pile | |---| | updateAllSetsScore | | updateUIScore | | updateUI | | viewDidLoad |

L'erreur a donc eu lieu alors qu'on était dans la méthode updateAllSetsScore de la classe ViewController.

OK, mais c'est quoi l'erreur ?

Xcode vous explique cette erreur tout en haut dans la console dès la première ligne :

Erreur affichée en première ligne de la console.

Cette erreur semble signifier qu'on essaye d'accéder à un élément dans un tableau à l'index 5, mais le plus grand index disponible est 4. Il faut que nous allions investiguer le code pour vérifier tout ça !

Compilation vs exécution

Avant de corriger notre erreur dans le prochain chapitre, je voudrais profiter de celle-ci pour vous parler d'une notion importante de programmation.

Notion de compilation

Une grande partie des langages de programmation, dont Swift, sont dits compilés. C'est-à-dire que le langage est d'abord traduit dans un langage compréhensible facilement par la machine, comme l'assembleur par exemple. On appelle cette étape la compilation ou (compile time en anglais).

Ensuite, ce code traduit est exécuté et le programme tourne. Dans notre cas, l'application est lancée ! Cette étape, c'est l'exécution (ou run time en anglais).

Schéma décrivant les étapes de compilation et exécution.

OK, mais ça sert à quoi la compilation ?

La compilation permet de générer un code très facile et donc très rapide à lire pour la machine, ce qui permet d'optimiser grandement le programme !

Deux types d'erreurs

Puisqu'il y a deux étapes, il y a deux types d'erreurs :

Les erreurs à la compilation (compile time error)

  • Elles peuvent être détectées par Xcode avant même de lancer le programme, car Xcode compile votre code après chaque modification.

  • Ces erreurs peuvent être des erreurs syntaxiques ou sémantiques : utilisation de mots interdits, code non interprétable, types non respectés, etc.

  • Elles sont signalées en rouge dans votre code à la ligne correspondante.

Les erreurs à l'exécution (run time error)

  • Elles ont lieu une fois que l'application est lancée, comme c'est le cas pour nous ici.

  • Ces erreurs sont en général dues à un problème logique dans le programme. Il est forcé d'essayer de faire une action interdite et donc il génère une erreur.

  • Elles font planter l'application et s'affichent dans la console.

Schéma résumant ce qu'on a dit sur les erreurs à la compilation et à l'exécution.

Dans un cours précédent, vous avez appris à gérer les erreurs à la compilation. Dans ce chapitre et dans le suivant, vous allez apprendre à résoudre les erreurs à l'exécution !

En résumé

  • Une pile d'exécution permet de mémoriser l'enchaînement d'appels des méthodes (ou fonctions) d'un programme.

  • Lors d'un plantage de votre application, la pile d'exécution et l'erreur sont affichées dans la console. Ces deux informations vous permettent de retracer le problème !

  • Swift est un langage compilé. Il est d'abord traduit en un code compréhensible facilement par la machine puis ce code est exécuté.

  • Il y a donc deux types d'erreurs : à la compilation et à l'exécution.

Dans le prochain chapitre, nous allons retracer encore plus précisément notre erreur grâce aux points d'arrêts et la résoudre !

Example of certificate of achievement
Example of certificate of achievement