Comment détecter les méthodes inutilisées et #import dans Objective-C

100

Après avoir travaillé longtemps sur une application iPhone, je me suis rendu compte que mon code est assez sale, contenant plusieurs #import et des méthodes qui ne sont pas appelées ou utiles du tout.

Je voudrais savoir s'il existe une directive de compilation ou un moyen de détecter ces lignes de code inutiles. Xcode a-t-il un outil pour détecter cela?

Hectoret
la source

Réponses:

66

Xcode vous permet de (dé) vérifier les paramètres pour les avertissements spécifiques du compilateur qui peuvent vous avertir de certains types de code inutilisé. (Sélectionnez le projet dans la liste source et File> Get Info, puis sélectionnez l'onglet Build.) En voici quelques-uns (qui apparaissent pour Clang et GCC 4.2 pour moi) qui peuvent être intéressants:

  • Fonctions inutilisées
  • Paramètres inutilisés
  • Valeurs inutilisées

Je ne vois aucune option pour détecter les importations inutilisées, mais c'est un peu plus simple - l'approche low-tech consiste simplement à commenter les instructions d'importation jusqu'à ce que vous obteniez une erreur / un avertissement de compilation.

Les méthodes Objective-C inutilisées sont beaucoup plus difficiles à détecter que les fonctions C inutilisées car les messages sont distribués dynamiquement. Un avertissement ou une erreur peut vous indiquer que vous avez un problème potentiel, mais l'absence d'un problème ne garantit pas que vous n'aurez pas d'erreurs d'exécution.


Edit: Un autre bon moyen de détecter les méthodes (potentiellement) inutilisées est d'examiner la couverture du code à partir des exécutions réelles. Cela se fait généralement en tandem avec des tests unitaires automatisés, mais ce n'est pas obligatoire.

Cet article de blog est une introduction décente aux tests unitaires et à la couverture de code à l'aide de Xcode. La section sur gcov(qui ne fonctionne qu'avec du code généré par GCC, soit dit en passant) explique comment obtenir Xcode pour construire un code instrumenté qui peut enregistrer la fréquence à laquelle il a été exécuté. Si vous prenez une version instrumentée de votre application pour un tour dans le simulateur, puis exécutez gcov dessus, vous pouvez voir quel code a été exécuté en utilisant un outil comme CoverStory (une interface graphique assez simpliste) ou lcov(des scripts Perl pour créer des rapports HTML) .

J'utilise gcovet lcovpour CHDataStructures.framework et je génère automatiquement des rapports de couverture après chaque commit SVN. Encore une fois, rappelez-vous qu'il n'est pas judicieux de traiter la couverture exécutée comme une mesure définitive du code "mort", mais cela peut certainement aider à identifier des méthodes que vous pouvez étudier plus en détail.

Enfin, puisque vous essayez de supprimer le code mort, je pense que vous trouverez cette question SO intéressante également:

Quinn Taylor
la source
4
Je ne suis pas sûr de votre point de vue ... L'analyseur statique peut trouver beaucoup de problèmes, mais si vous envoyez un message à une variable typée comme id, ou créez un sélecteur à appeler au moment de l'exécution, l'analyseur statique ne peut pas garantir que le code est vraiment inutilisé. Si le code qui est toujours nécessaire est supprimé, c'est là que vous obtiendrez des erreurs d'exécution. Est-ce que je manque quelque chose?
Quinn Taylor
1
De plus, les sélecteurs créés à partir de chaînes au moment de l'exécution sont assez courants.
dreamlax le
1
Bien sûr, il y a des cas où votre code dynamique pourrait être mieux servi en étant plus fortement typé (c'est-à-dire renvoyer quelque chose au lieu d'un identifiant). Le typage à l'exécution est un point fort de la programmation Cocoa / Objective-C, mais parfois la maintenance et la lisibilité seraient mieux servies en pensant davantage au typage fort.
alesplin le
3
Oh, je suis définitivement d'accord. Ma règle de base est de taper statiquement (comme je le ferais en Java) à moins que j'aie vraiment besoin d'une frappe dynamique, ce qui est rare mais arrive à l'occasion. Cependant, le simple fait d'interfacer avec les classes Cocoa (par exemple, la spécification d'un délégué) peut entraîner un dynamisme et des chemins d'exécution difficiles à tracer. Heck, tout programme avec une boucle d'exécution et plusieurs threads peut être non trivial ...
Quinn Taylor
40

Appcode a une fonction d'inspection de code qui trouve les importations et le code inutilisés.

patrick-fitzgerald
la source
18
Donc, vous voulez dire que nous devrions installer Appcode uniquement pour cette fonctionnalité?
mayqiyue
Si cela vous est utile, oui!
rmp251
5

J'ai récemment écrit un script pour trouver des #importdéclarations inutilisées (ou en double) : https://gist.github.com/Orangenhain/7691314

Le script prend un fichier ObjC .m et commence à commenter chaque #importligne tour à tour et à voir si le projet se compile toujours. Vous devrez changer BUILD_DIR et BUILD_CMD.

Si vous utilisez une findcommande pour laisser le script s'exécuter sur plusieurs fichiers, assurez-vous d'utiliser un BUILD_CMD qui utilise réellement tous ces fichiers (ou vous verrez un fichier avec de nombreuses instructions d'importation inutilisées).

J'ai écrit ceci sans savoir qu'AppCode a une fonctionnalité similaire, mais quand j'ai testé AppCode, ce n'était pas aussi complet que ce script (mais beaucoup plus rapide [pour tout un projet]).

Orangenhain
la source
Il ne fonctionne que pour les doublons, les importations inutilisées ne sont pas supprimées.
Rahul
1

Récemment, j'ai changé un grand projet de Carbon à Cocoa. À la fin de cela, il y avait pas mal de fichiers orphelins qui n'étaient plus utilisés. J'ai écrit un script pour les trouver qui ont essentiellement fait ceci:

Assurez-vous que la source est entièrement archivée dans subversion (c.-à-d. Propre) Assurez-vous qu'elle se construit actuellement sans erreur (c.-à-d. Que xcodebuild renvoie le statut 0) Ensuite, pour chaque fichier source dans le répertoire, vide (c.-à-d. Supprimez le contenu, tronquez la longueur) le source et le fichier d'en-tête, essayez une compilation, si elle échoue, restaurez les fichiers, sinon, laissez-les vides.

Après avoir exécuté cela, rétablissez puis supprimez tous les fichiers vidés, compilez puis supprimez tous les #imports erronés.

Je devrais également ajouter que vous devez éviter les fichiers référencés à partir de fichiers .xib ou .sdef, et il peut y avoir d'autres cas de liaison dynamique, mais cela peut toujours vous donner une bonne idée de ce qui peut être supprimé.

La même technique peut être utilisée pour voir quels #imports peuvent être supprimés - au lieu de tronquer le fichier, supprimez tour à tour chaque #import du fichier et voyez si la construction échoue.

Peter N Lewis
la source