Il s’agit d’un article de blog posté par un membre de l’équipe Tutoriel de iOS Matt Galloway, fondateur de SwipeStack, une équipe de développement d’application mobile basée à Londres, Royaume-Uni.

Learn how to troubleshoot and optimize your code with Xcode Instruments!
À ce stade de votre carrière au développement iOS, vous avez probablement écrit une application ou deux, et vous vous demandez sans doute ce que vous pouvez faire pour rendre vos applications encore mieux.
Outre l’amélioration de votre application en ajoutant des fonctionnalités, il ya une chose que tous les développeurs d’applications doivent faire … instrumenter leur code!
Ce tutoriel va vous montrer comment utiliser les fonctions les plus importantes de l’outil appelé Instruments livré avec Xcode. Il vous permet de vérifier votre code pour les problèmes de performance, les fuites de mémoire ou d’autres problèmes.
Dans ce tutoriel, vous allez apprendre:
- Comment détecter et corriger les problèmes de gestion de la mémoire dans votre code en utilisant les instruments d’allocation et de fuites, et
- Comment déterminer les points chauds dans votre code en utilisant l’instrument “Time profiler”et la façon de rendre votre code plus efficace.
Notez: Ce tutoriel suppose que vous êtes compétent en Objective-C et en programmation iOS. Si vous êtes un débutant complet à la programmation IOS, vous pourriez jeter un coup d’oeil sur les autres tutoriels sur ce site. Ce tutoriel permet l’utilisation d’un storyboard, alors assurez-vous que vous êtes familier avec le concept, un bon endroit pour commencer est avec le tutoriel sur ce site.
Ce tutoriel va utiliser Xcode 4.5, alors assurez-vous entièrement mis à jour avec la dernière version, qui est disponible via le Mac App Store.
Etes vous pret? Préparez-vous à plonger dans le monde fascinant des instruments! :]
Prise en main
Pour ce tutoriel, vous n’aurez pas à suivre le processus de création d’une application à partir de zéro, mais plutôt utiliser un exemple de projet prévu pour vous. Votre tâche est de parcourir l’application et de l’améliorer en utilisant les instruments de guide – très semblable à la façon dont vous vous y prendriez pour l’optimisation de vos propres applications!
Télécharger le projet de démarrage puis décompressez-le et ouvrez-le dans Xcode.
Générez et exécutez l’application, effectuez une recherche, cliquez sur le résultat, et vous verrez quelque chose comme ce qui suit:

Naviguez à travers l’application et de vérifier les fonctions de base. Comme vous pouvez le voir, la caractéristique essentielle de l’application est de rechercher et d’afficher des photos sur Flickr. Il ya une barre de recherche en haut de l’application, et lorsque vous effectuez une recherche, une nouvelle ligne de résultats apparaissent dans le tableau.
Cette nouvelle ligne dans le tableau affiche le terme de recherche, et le nombre de résultats trouvés entre parenthèses. Si vous tapez sur une cellule, les résultats de la recherche s’expand et vous présente une autre table, l’affichage des titres d’image ainsi que des images de prévisualisation.
Si vous tapez sur l’un des résultats de prévisualisation, l’application vous amène sur une vue plein écran de l’image. De ce point de vue, vous pouvez faire pivoter l’image si vous le souhaitez.
Jusqu’ici tout va bien! :] Vous pouvez voir que l’application fonctionne comme prévu. Vous pourriez être tenté de penser qu’une fois l’interface de l’utilisateur est superbe, l’application est prête à être soumise à Apple. Cependant, vous êtes sur le point de voir la valeur que l’utilisation d’instruments peut ajouter à votre application.
Le reste de ce tutoriel va vous montrer comment trouver et corriger les problèmes qui subsistent dans l’application. Vous verrez comment les instruments peuvent faire des problèmes de mise au point d’un ensemble beaucoup plus facile à fixer! :]
Temps de profilage

Beaucoup de développeurs commencent avec une idée vague que leur application devrait aller vite – et c’est un objectif louable. Puis ils lisent quelque chose appelé “l’optimisation prématurée” et se demandent comment cette chose terrible que les programmeurs barbon se froncent les sourcils peut être évitée. Dans le pire des cas, les développeurs débutants oublier l’optimisation tout à fait!
Dans une certaine mesure, vous pouvez laisser l’optimisation hors de votre processus de développement d’applications, il ya dix ans, les appareils mobiles ont été incroyablement limité, et même l’utilisation de nombres à virgule flottante a été interdit parce qu’il rend plus grand la taille du code et les calculs deviennent énormes .
Maintenant, vous détenez une quantité incroyable de puissance dans votre poche, avec du matériel 3D assez bon pour battre le meilleur matériel d’ordinateur de bureau de pas si longtemps. Mais vous ne pouvez pas toujours compter sur le matériel et la vitesse du processeur et passer sous silence les bits inefficaces dans votre application.
Pour finir qu’est ce «profilage», de toute façon? Le profilage est un moyen de mesurer. Le résultat d’une session de profilage permet de mieux comprendre quelles parties de votre code sont utilisés le plus souvent, à leur tour, il vous indique quelles parties du code Vous devriez essayer de l’améliorer.
Vous pouvez passer une semaine peaufiner un algorithme intéressant, mais si ce code n’occupe que 0,5% du temps total d’exécution, personne ne saura jamais la différence, peu importe comment vous l’avez amélioré. Si au contraire vous avez passé l’effort pour optimiser le boucle où votre programme passe 90% de son temps, et faite seulement une amélioration de 10% votre mise à jour aura la chance d’attirer des revues à cinq étoiles car il sera remarqué beaucoup plus vite!
La première leçon de l’optimisation est la suivante: trouver les bons endroits pour le faire! :]
L’optimisation prématurée, vous aurez deviné, est de passer du temps pour optimiser les parties qui n’ont vraiment pas d’importance à la fin.
Le premier instrument que vous regardez est le “Profiler Time”. À des intervalles mesurés, l’exécution du programme est interrompue, et une trace de pile est effectué sur chaque issue. Pensez-y comme appuyant sur le bouton pause dans le débogueur de Xcode.
Voici un aperçu de “Time Profiler”:


Cet écran affiche la pile des appels de chaque thread. Chaque niveau, ou frame, comme on l’appelle, il existe un procédé différent que le trajet d’exécution du programme a suivi pour arriver au point où le CPU est en train d’exécuter le code – c’est-à-frame 0.
Le temps passé dans chaque méthode peut alors être déterminée à partir du nombre de fois que le profileur est arrêtée dans chaque méthode.
Par exemple, si 100 échantillons sont effectuées à intervalles de 1 milliseconde et une méthode particulière est jugée au sommet de la pile dans 10 échantillons, alors vous pouvez en déduire que près de 10% du temps total d’exécution – 10 millisecondes – ont été consacrés dans cette méthode. Il s’agit d’une approximation assez brute, mais elle fonctionne!
Donc, sans plus tarder, il est temps de s’habituer à l’instrumentation!
Depuis la barre de menus de Xcode, sélectionnez ProductProfile, ou appuyez sur⌘I. Cela va executer l’application et et lancer les instruments . Vous serez accueillis avec une fenêtre de sélection qui ressemble à ceci:

Ceux -ci sont tous des modèles différents qui viennent avec les instruments.
Sélectionnez l’Time Profiler instrument et cliquez surProfile. Cela lancera le simulateur iOS et démarrera l’application. Vous pourriez être invité à fournir votre mot de passe pour autoriser Les instruments à d’autres à analyser d’autres procédés – Pas de crainte, il n’ya pas de danger à le fournir ici! :]
Dans la fenêtre des instruments, vous pouvez voir le decomptage du temps, et une petite flèche se déplaçant de la gauche vers la droite au-dessus du graphique dans le centre de l’écran. Cela indique que l’application est en cours d’exécution.
Maintenant, commencez à utiliser l’application. Rechercher des images, et naviguer dans l’un ou plusieurs des résultats de recherche. Vous auriez sans doute remarqué que l’acces aux résultat de recherche est péniblement lent, et défilement dans la liste des résultats de la recherche aussi incroyablement ennuyeux – c’est une application vraiment terrible et maladroite !
Eh bien, vous avez de la chance, car vous êtes sur le point de vous engager à le fixer! Cependant, vous allez obtenir un résumé rapide de ce que vous regardez dans les instruments .
Tout d’abord, Vérifiez que l’affichage de la barre d’outils du sélecteur possède les trois options choisies, comme ici.:

Cela permettra de s’assurer que tous les panneaux sont ouverts. À présent étudiez la capture d’écran ci-dessous et l’explication de chaque section en dessous:


- Il s’agit de la commande d’enregistrement. Le bouton du milieu rouge arrête & amp; démarre l’application actuellement en cours de profilage quand on clique dessus. Il s’agit en fait d’arrêt et démarrage de l’application – PAS l’interruption.
- Il s’agit de la minuterie du temps et du Navigator. La minuterie Compte combien de temps l’application est en cours de profilage et en cours d’exécution. Les flèches se deplacent entre les cycles . Si vous arrêtez, puis redémarrez l’application utilisant le contrôle de l’enregistrement, qui commencerait une nouvelle course. L’affichage montrera alors “Run 2 sur 2″, mais vous pouvez récupérer les données de la première manche en commençant par arrêter votre course en cours, puis appuyez sur la flèche gauche pour revenir en arrière.
- C’est ce qu’on appelle rapeller une piste. Dans le cas du modèle que vous avez choisi dans le profiler de temps, il ya juste un instrument de sorte qu’il ya une seule piste. Vous en apprendrez plus sur les spécificités du graphe présentés ici dans le tutoriel terres.
- Voici le détail de l’extension du panneau . Dans ce cas de l’instrument de profiler du temps est utilisé pour montrer traces de la pile, car c’est ce qui est enregistrer par les instruments.
- C’est le panneau de détails. Il montre les principales informations sur l’instrument particulier que vous utilisez. Dans ce cas, il est montre les méthodes qui sont “plus chaud” – c’est-à ceux qui ont utilisé plus de ressources CPU si vous cliquez sur la barre en haut qui dit “Arborescence des appels” (celui de gauche) et Sélectionnez «Sample List», alors vous êtes fournis avec une vue différente des données. Ce point de vue est affiche chaque échantillon. Cliquez sur quelques échantillons, et vous verrez la trace de la pile de capture apparaîtra dans le détail de l’extension du panneau.
- C’est le panneau d’options. Vous allez en apprendre davantage sur ces options sous peu.
Maintenant fixons la maladroite UI! :]
Exploration Approfondie
Effectuez la recherche d’images et approfondie dans les résultats. Personnellement J’aime chercher pour “chien”, mais Choisissez ce que vous voulez – vous pourriez être une de ces personnes qui aime le chat! :]
Maintenant, faire défiler la liste à quelques reprises afin que vous disposez d’une bonne quantité de données dans le profiler de temps. Vous devriez remarquer les chiffres dans le milieu de l’écran qui changent et le remplissage du graphique, ce qui vous dit que les cycles de CPU sont utilisés.
Vous ne vous attendez pas vraiment ne à ce que l’ interface utilisateur soit aussi maladroite que cela; Aucun affichage du tableau n’est prête à à etre expédié jusqu’à ce qu’elle défile comme du beurre! Pour aider à cerner le problème, vous devez définir certaines options sur les perspectives de profiler de temps.
En dessous Arborescence des appels section sur la gauche, sélectionnezSéparé par fil de discussion, Inverser Arborescence des appels, Masquer les bibliothèques système et Montrer Obj-C seulement. Il devrait ressembler à ceci:

Voici ce que chaque option fait avec les données affichées sur la table vers droite:
- Séparé par fil de discussion: Chaque thread doit être considéré séparément. Ceci vous permet decomprendre les threads qui sont responsables de la plus grande quantité d’utilisation CPU.
- Inverser Arborescence des appels: Avec cette option, la trace de la pile est considérée comme de haut en bas. Cela signifie que vous verrez les méthodes de la table qui aurait été dans la trame 0 lorsque l’échantillon a été prélevé. C’est généralement ce que vous voulez, comme vous voulez voir les plus methodes particulieres où le processeur passe son temps.
- Masquer Symboles Manquants: Si le fichier dSYM ne peut être trouvée pour votre application ainsi que le système de Framework donc au lieu de voir les noms des méthodes (symboles) dans la table, vous ne verrez que les valeurs hexadécimales. Ceux-ci correspondent à l’adresse de l’instruction Dans le code binaire. Si cette option est sélectionnéedonc ceux-ci sont cachés, seulement les symboles entièrement résolus sont affichés . Cela contribue à désencombrer les données affichées.
- Masquer les bibliothèques système: Lorsque cette option est sélectionnée, seuls les symboles de votre propre application sont affichés . Il est souvent utile de sélectionner cette option, car habituellement vous ne s’intéressé que là où le CPU passe du temps dans votre propre code – vous ne pouvez pas faire grand-chose sur la quantité CPU utilsée par le système des bibliothèques!
- Afficher Obj-C Seulement: Si cette option est sélectionnée, seules les méthodes Objective-C sont affichés, Au lieu de n’importe quel fonctions C ou C + + . Il n’en existe pas dans votre programme, mais si vous cherchez une application OpenGL, il pourrait avoir quelques exemples C + +, par exemple.
- Aplatir la récursivité: Cette option traite les fonctions récursives (ceux qui s’appellent eux-mêmes) comme une entrée dans chaque trace de la pile, Au lieu de multiples.
- Fonctions Premières (du haut): L’activation de ceci fait que les instruments considèrent le temps total passé dans la fonction comme la somme du temps directement au sein de cette fonction, ainsi que le temps passé dans les fonctions appelées par cette fonction. Ainsi si A appelle la fonction B, ainsi si le temps de A est reporté correspond au temps passé en A en PLUS du temps passé dans B. Cela peut être très utile, car elle vous permet de choisir le chiffre le plus grand à chaque fois que vous descendez dans la pile d’appel, se concentrant sur vos les methodes les plus fastidieuses .
Cependant certaines valeurs peuvent être légèrement différents, l’ordre des inscriptions devrait être similaire à la table ci-dessous une fois que vous avez activé les options ci-dessus:

Eh bien, ce n’est certainement pas l’air trop bon. La grande majorité du temps est passé dans la cellule du tableau qui définit la photo. Cela devrait pas venir comme choc pour vous, puisque le tableau défilant était la partie maladroite de l’interface, et c’est là que les cellules du tableau sont constamment mis à jour.
Pour en savoir plus sur ce qui se passe Dans cette méthode, double-cliquez sur la colonne. Cela fera apparaître l’ affichage suivant:

Eh bien, c’est intéressant, n’est-ce pas! Près des trois quarts du temps passé dans le setPhoto: méthode à été utilisée pour créer les données d’image pour la photo!
Maintenant vous pouvez voir quel est le problème. NSData’s dataWithContentsOfURL NSData blocs(c’est-à ne PAS retourner) jusqu’à ce que les données ont été Téléchargées. Étant donné que cette demande va vers l’Internet pour saisir les données, chaque appel pourrait prendre jusqu’à quelques secondes pour revenir. Cette méthode est exécutée sur le thread principal, et par conséquent l’interface de l’utilisateur est entièrement empêchés de d’être mise à jour, tandis que les données d’image Téléchargées.
Pour résoudre ce problème, une classe a été prévue appelé ImageCache qui permet le téléchargement asynchrone des images sur un thread en’arrière,caché. Le code existe dans la cellule photo-électrique de classe.
Vous pouvez maintenant passer à Xcode manuellement et trouvez le fichier, mais les instruments le rendent plus simple Pratiques “dans Xcode Ouvert” juste devant vos yeux. Localiser le dans le panneau juste au dessus du code et cliquez sur la dessus:

C’est parti! Xcode s’ouvre exactement au bon endroit. boom!
Maintenant, commentez les deux lignes qui attirent l’NSData et définissez l’image, et décommenter le bloc de code ci-dessous. La méthode setPhoto alors ressembler à ceci
:
- (void)setPhoto:(FlickrPhoto *)photo {
_photo = photo;
self.textLabel.text = photo.title;f
// NSData *imageData = [NSData dataWithContentsOfURL:_photo.thumbnailUrl];
// self.imageView.image = [UIImage imageWithData:imageData];
[[ImageCache sharedInstance] downloadImageAtURL:_photo.thumbnailUrl
completionHandler:^(UIImage *image) {
self.imageView.image = image;
[self setNeedsLayout];
}];
} |
Ré-exécutez l’application dans en appuyantProductProfile (ou ⌘I – Rappelez-vous, ces raccourcis vont vraiment vous faire économiser du temps).
Notez que cette fois vous n’êtes pas invité par exemple à choisir quel instrument utiliser. C’est parce que vous avez toujours une fenêtre ouverte pour cette application, et les instruments supposent que vous voulez exécuter à nouveau avec les mêmes options.
Effectuez quelques recherches supplémentaires, et remarquez que cette fois l’interface de l’utilisateur n’est pas tout à fait aussi maladroite! Les images désormais se téléchargent de manière asynchrone et mis en cache dans le fond, donc une fois qu’ils ont été une fois Téléchargées Ils n’ont pas à être Re-téléchargées.
Il semble parfait! Est-il temps pour l’expédier? pas encore! :]
Allocations, Allocations, Allocations
Le prochain instrument couvert dans ce tutoriel est l’instrument allocations. Cela vous donne des informations détaillées sur tous les objets qui sont créés et la mémoire qui les appuient; Il affiche également les compte conservé de chaque objet.
La meilleure façon de repartir à zéro avec un nouveau profil d’instruments est de simplement fermer Instruments et recommencer. Fermer les Instruments retourner sur Xcode et sélectionnezProductProfile à nouveau. Ensuite, sélectionnez allocations à partir du sélecteur et cliquez surProfile.

Les instruments seront affichés une fois de plus et vous serez accueilli par ce qui suit:


Cette fois, vous remarquerez deux pistes. L’un est appeléAllocations, et l’autre est appeléVM Tracker. La piste allocations seront discutés en détail dans ce tutoriel, le tracker VM est aussi très utile, mais c’est un peu plus compliqué.
Alors quel anomalie allez vous dépister maintenant? :]
Il ya quelque chose de caché dans le projet que vous ne savez probablement pas l’existance. Vous avez probablement entendu parler des fuites de mémoire. Mais ce que vous ne pouvez pas savoir, c’est qu’il ya en fait deux types de fuites.
La première est la fuite de la mémoire vraie, où un objet n’a pas encore été libéré, mais n’est plus référencé par quelque chose d’autre. Par conséquent la mémoire ne peut jamais être réutilisée.
Le deuxième type de fuite est un peu plus compliquée. C’est ce qu’on appelle la «croissance sans limite de mémoire”. Cela se produit lorsque la mémoire continue à être allouée et n’est jamais donné une chance d’être libérée.
Si cela continue toujours, puis à un moment la mémoire du système sera remplie et vous aurez un problème de mémoire considérable sur vos mains. Dans iOS, cela signifie que l’application va être tué par le chien de garde du système. Cela n’entraînera pas votre application d’obtenir cinq étoiles! :]
Mettre en place un scénario dans lequel vous pouvez détecter la croissance de mémoire illimitée. Tout d’abord, effectuer 10 recherches différentes dans l’application (mais ne pas s’attarder dans les résultats encore). Assurez-vous que les recherches proposent des résultats! Maintenant laissez l’application s’installer un peu en attendant quelques secondes.
Vous avez sans doute remarqué que le graphe de la piste allocations a augmenté. C’est vous dire que la mémoire est allouée. C’est cette fonction qui vous guidera pour trouver la croissance de mémoire illimitée.
Ce que que vous allez réaliser est une «analyse de segment “. Pour ce faire, appuyez sur le bouton “Mark Heap”. Vous trouverez sur le bouton sur le côté gauche du panneau de détails:


Pressez-le et vous verrez un drapeau rouge apparaitre dans la piste, comme ceci:


Le but de l’analyse du segment de mémoire est d’effectuer une action plusieurs fois, et voir si la mémoire s’expend de plus en plus de façon illimitée. Passer du temps dans la recherche, attendre quelques secondes pour que les images se chargent, puis retourner sur la page principale. Ensuite, marquez le segment à nouveau. Pour ce faire, à plusieurs reprises pour différentes recherches.
Après un bon nombre de recherches approfondies , Les instruments se présentent comme suit:


À ce stade, vous devriez commencer à avoir des soupçons. Remarquez comment le graphique bleu va avec chaque recherche que vous éffectués. Si vous continuez ce pour les 10 recherches, vous vous retrouverez avec un graphique qui ressemble à ceci:


Eh bien, ce n’est certainement pas bon. Mais attendez, et les avertissements de de mémoire? Vous avez des connaissances sur cela , oui? Avertissements de mémoire sont une manière de iOS de dire à une application que les choses vont serré dans le département de de mémoire, et vous avez besoin de vider un peu de mémoire.
Il est possible que cette croissance n’est pas seulement à cause de votre application, il pourrait être quelque chose dans les profondeurs de UIKit qui est retenue sur la mémoire. Donner des cadres du système et votre application une chance d’effacer leur mémoire avant de pointer du doigt un ou l’autre.
Simuler un avertissement de mémoire en sélectionnant Avertissement Mémoire HardwareSimulate barre de menus du simulateur de iOS. Vous remarquerez que des baisses d’utilisation de mémoire un peu, mais certainement pas au niveau où il devrait être. Il exist toujours une augmentation de la mémoire qui se passe encore quelque part.
La raison de faire une vue par section (clichés) après chaque itération de de recherches approfondies , c’est que vous pouvez voir quel mémoire a été allouée entre chaque section. Jetez un coup d’oeil dans le panneau de détails et vous verrez un tas de clichés de segment.
Hit Me With Your Best Shot
La première est la prise de vue de base. Ouvrez le vous verrez tous les objets qui ont été allouées et qui résident toujours au moment où a été prise le cliché . Photos de segment suivantes contiennent uniquement les objets entre la prise de vue du cliché précédent et celle en cours.
Regardez la colonne “Heap Growth” et vous verrez qu’il ya certainement croissance se produisant quelque part. Ouvrez l’un des coups du cliché et vous verrez ce:


Wow, c’est beaucoup d’objets! Par quoi commencer?
La meilleure chose à faire est de regarder dans la liste des classes que vous utilisez dans votre application directement. Dans ce cas, HTTPHeaderDict, CGRegion, CGPath, CFNumber, etc peuvent tous être ignorés pour l’instant.
Cependant, l’celle qui se distingue est UIImage, comme c’est certainement quelque chose qui est abordée dans votre application. Cliquez sur la flèche à gauche de UIImage pour afficher la liste complète. Sélectionnez l’un et regardez le panneau de détails élargi:

Cette page vous donne une trace de la pile au moment où cet objet UIImage spécial a été créé. Les parties de la trace de la pile en gris dans les bibliothèques du système, les parties en noir sont dans le code de votre application. Pour obtenir plus de contexte pour cette trace, double-cliquez sur le cadre seulement noir qui est dans la méthode de la classe ImageCache. Cela vous mènera au code pour cette méthode, qui ressemble à ceci:
- (void)downloadImageAtURL:(NSURL*)url completionHandler:(ImageCacheDownloadCompletionHandler)completion {
UIImage *cachedImage = [self imageForKey:[url absoluteString]];
if (cachedImage) {
completion(cachedImage);
} else {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
[self setImage:image forKey:[url absoluteString]];
dispatch_async(dispatch_get_main_queue(), ^{
completion(image);
});
});
}
} |
Les instruments sont très utiles, mais ils ne peuvent pas vous aider davantage dans ce cas! Vous allez maintenant devoir travailler dans le code vous-même afin de comprendre ce qui se passe.
Jetez un coup d’oeil par la méthode ci-dessus, et vous verrez l’appel d’une méthode appelée setImage: forKey:. Cette méthode met en cache une image dans le cas où il est utilisé à nouveau plus tard dans l’application. Ah! Bien cela semble certainement que ça pourrait être un problème! :]
Jetez un oeil à la mise en place de cette méthode:
- (void)setImage:(UIImage*)image forKey:(NSString*)key {
[_cache setObject:image forKey:key];
} |
Cela ajoute une image à un dictionnaire qui est calé sur l’URL d’où l’image est venue. Mais si vous regardez dans le code, vous remarquerez que l’image n’est jamais effacée de ce dictionnaire!
C’est là que la croissance de votre de mémoire provient! Tout fonctionne comme il se doit, mais l’application ne n’élimine pas de la mémoire dans le cache – il n’ en fait qu’ajouter !
Pour résoudre le problème, tout ce que vous devez faire est ont ImageCache écouter la notification d’avertissement de mémoire envoyée par UiApplication . Lorsque ImageCache la reçoit, il doit être un bon citoyen et effacer le cache.
Pour faire que ImageCache écoute la notification, modifier la méthode init pour qu’elle ressemble à ceci:
- (id)init {
if ((self = [super init])) {
_cache = [NSMutableDictionary new];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(memoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
}
return self;
} |
Cela permet d’enregistrer laUIApplicationDidReceiveMemoryWarningNotification d’executer la methodememoryWarning:. Maintenant, mettre en œuvre cette méthode comme ci-dessous:
- (void)memoryWarning:(NSNotification*)note {
[_cache removeAllObjects];
} |
Tout ce que memoryWarning fait est de supprimer tous les objets dans le cache. Cela permettra d’assurer que rien ne s’accroche plus aux images et elles seront désaffectées (Désalouées).
Pour tester ce correctif, lancez Les instruments à nouveau (à partir de Xcode avec ⌘ I) et répétez les étapes que vous avez suivies précédemment. N’oubliez pas de simuler un avertissement de mémoire à la fin!
Note: Assurez-vous de lancer à partir de Xcode, déclenchant une compilation, plutôt que d’appuyer sur le bouton rouge dans Les instruments, afin de vous assurer que vous utilisez la dernière de code.
Cette fois, le l’analyse du cliché devrait ressembler à ceci:


Cette fois-ci, l’d'utilisation de mémoire a chuté de façon spectaculaire après l’avertissement de mémoire. Il ya encore une certaine croissance globale de la mémoire, mais loin de ce que l’on avait avant.
La raison pour laquelle il ya encore une certaine croissance est vraiment due aux bibliothèques système, et il n’y a pas beaucoup que vous pouvez faire pour ceux-ci. Il semble que les bibliothèques du système ne se libèrent pas toute libérant de leur mémoire, qui peut être par leur conception ou peut avoir un bug. Tout ce que vous pouvez faire dans votre application est dégager autant de mémoire que possible, et c’est ce que vous avez déjà fait! :]
Bien fait! Une autre question subsiste! Il doit être temps d’expédier l’application maintenant ! Oh, attendez – il ya toujours la question du premier type de fuite que vous n’avez pas encore abordé.
Appelez le plombier – Vous avez une fuite!
Le prochain instrumentvous allez regarder est l’instrument des fuites. Cette fonction est utilisée pour trouver le premier type de fuite mentionné plus tôt – le genre qui se produit quand un objet n’est plus référencé par quoi que ce soit, et consomme de la mémoire.
Détection de fuites est naturellement une affaire très complexe, mais l’outil de fuites se souvient de tous les objets qui ont été allouées et périodiquement parcourt chaque objet pour déterminer s’il ya lieu n’est pas accessible à partir de tout autre objet.
Fermer les instruments retourner sur Xcode et sélectionnez ProductProfile. Sélectionnez le modèle de fuites et cliquez sur Profil:

Les instruments se déclenchent avec 2 pistes – Allocations et Leaks. La piste des allocations est le même que celui qui vient dans le modèle de répartition utilisée dans la section précédente.
Vous ne serez préoccupé que par la piste des fuites dans cette section, cliquez donc sur cette piste pour le mettre en surbrillance. Notez que les détails que vous voyez dans le reste de la fenêtre des instruments maintenant changent pour refléter l’état de la piste.
Dans le panneau de détails, vous verrez que Automatic Snapshotting est mis en marche. Cela signifie que les fuites sont détectées automatiquement de temps en temps.
L’intervalle entre les clichés peuvent être modifiés, mais la valeur par défaut de 10 secondes est assez bon pour vos besoins en ce moment. Vous pouvez forcer un cliché à chaque fois que vous le souhaitez en appuyant sur la toucheSnapshot Now bouton.
Retour sur votre application! Effectuez une recherche et verifiez les résultats. Appuyez ensuite sur l’une des lignes aperçu résultat pour ouvrir la colonne en plein écran. Appuyez sur le bouton de rotation en haut à gauche, puis appuyez à nouveau.
Retourner aux instruments et attendez un instant. Si vous avez fait correctement les étapes précédentes, vous remarquerez qu’une fuite est apparue! Votre fenêtre Instruments se présentent comme suit:


Retour au simulateur et appuyez sur Pivoter à quelques reprises. Revenez ensuite à aux instruments et attendez. Encore quelques fuites devrait apparaître, qui ressemblent à ceci:


Où est la fuite vient-elle? Si le volet d’information élargi (à droite) n’est pas ouvert, n’oubliez pas que le contrôle du choix de vue “view selector” vous permet de s’y rendre:

Ouvrez la liste CGContext dans le panneau de détails prolongée. Sélectionnez l’un des éléments CGContext dans la liste et regardez le panneau de détails élargiqui montre la trace de pile qui a provoqué l’objet crée, comme ci-dessous:


Une fois de plus, les frames qui se rapportent à votre code sont représentés en noir. Comme il n’y en a qu’une, double-cliquez dessus pour voir le code pour cette méthode.
Le procédé en question est rotateTapped:, qui est le gestionnaire appelée lorsque le bouton de rotation est exploité. Ce procédé fait tourner l’image d’origine et crée une nouvelle image, comme ci-dessous:
- (void)rotateTapped:(id)sender {
UIImage *currentImage = _imageView.image;
CGImageRef currentCGImage = currentImage.CGImage;
CGSize originalSize = currentImage.size;
CGSize rotatedSize = CGSizeMake(originalSize.height, originalSize.width);
CGContextRef context = CGBitmapContextCreate(NULL,
rotatedSize.width,
rotatedSize.height,
CGImageGetBitsPerComponent(currentCGImage),
CGImageGetBitsPerPixel(currentCGImage) * rotatedSize.width,
CGImageGetColorSpace(currentCGImage),
CGImageGetBitmapInfo(currentCGImage));
CGContextTranslateCTM(context, rotatedSize.width, 0.0f);
CGContextRotateCTM(context, M_PI_2);
CGContextDrawImage(context, (CGRect){.origin=CGPointZero, .size=originalSize}, currentCGImage);
CGImageRef newCGImage = CGBitmapContextCreateImage(context);
UIImage *newImage = [UIImage imageWithCGImage:newCGImage];
self.imageView.image = newImage;
} |
Encore une fois, les instruments ne peuvent que vous donner un indice ici pour savoir où se trouve le problème, il ne peut pas vous dire exactement où la fuite est. Ils sont seulement en mesure de vous montrer où l’objet de la fuite a été créé . Il est alors de votre devoir de travailler à ce que de resoudre le problème ! :]
Vous pensez peut-être que l’ARC aurait dû prendre soin de toute la gestion de la mémoire, et qu’il ne pouvait pas exister une fuite dans le code … c’est exact?
Rappelons que l’ARC ne traite que des objets Objective-C. Il ne gère pas le retention et la libération des objets du CoreFoundation qui ne sont pas des objets d’Objective-C.
Ah, ça commence à devenir évident ce qu’est le problème – le CGContextRef et objets CGImageRef ne sont jamais libérés! Pour corriger cela, ajoutez les deux lignes de code suivantes à la fin de la méthode rotateTapped:
CGImageRelease(newCGImage);
CGContextRelease(context); |
Ces deux appels sont nécessaires pour équilibrer les comptes retenus de ces deux objets. La morale de cette histoire est que vous avez encore besoin de connaître le comptage de référence – même si vous utilisez ARC dans votre projet!
Au sein Xcode, utilisez ⌘ à nouveau pour générer et exécuter l’application dans les instruments.
Regardez l’application à nouveau dans les instruments en utilisant les instruments de fuites et voyez si cette fuite a été corrigé. Si vous avez suivi correctement les étapes précédentes, la fuite devrait avoir disparu!
Bien joué! SHIP IT! :]
Où aller à partir d’ici?
Maintenant que vous avez cette connaissance sous votre ceinture, allez et instrumenter votre propre code et voir les les choses intéressantes qui apparaissent! Aussi, essayez de faire des instruments une partie du votre flux de travail habituel le développement.
Vous devriez exécuter votre code à travers les instruments assez souvent, et en effectuant un balayage complet de votre application avant la sortie pour s’assurer que vous avez pris en consideration la gestion de la mémoire et les nombreux problèmes de performance autant que possible.
Maintenant, allez faire d’ impressionnantes et efficaces- apps! :]

Il s’agit d’un article de blog par un membre de l’équipe Tutoriel de iOS Matt Galloway, foundateurSwipeStack, une équipe de développement d’application de mobile basée à Londres, Royaume-Uni.