Introduction : pourquoi le profilage du code Swift est la compétence n°1 pour un développeur iOS/macOS
Les applications iOS et macOS modernes deviennent de plus en plus complexes, et les utilisateurs de plus en plus exigeants. Personne n'attendra 5 secondes qu'un écran se charge, ni ne tolérera une animation saccadée. L'optimisation des performances n'est pas un luxe, mais une nécessité. Mais comment savoir quelle partie du code ralentit toute l'application ? La réponse est le profilage du code Swift.
Le profilage est le processus de collecte de données sur le fonctionnement d'un programme : temps d'exécution des fonctions, utilisation de la mémoire, fréquence des appels. Sans lui, toute tentative d'optimisation devient une divination. Dans cet article, nous allons passer en revue les outils et techniques pratiques qui vous aideront à trouver les goulots d'étranglement dans le code Swift pour iOS et macOS. Vous apprendrez à utiliser Instruments, os_signpost et les outils intégrés de Xcode, et vous verrez des exemples de code concrets.
1. Outils de profilage Swift dans Xcode
Xcode fournit un ensemble puissant d'outils de profilage, regroupés dans l'application Instruments. Voici les principaux qui seront utiles à chaque développeur :
- Time Profiler — montre combien de temps processeur est consacré à chaque fonction. Idéal pour trouver les « points chauds » (hot spots).
- Allocations — suit l'allocation et la libération de la mémoire. Aide à trouver les fuites et la consommation excessive.
- Leaks — recherche automatiquement les fuites mémoire (cycles de rétention).
- Core Animation — analyse les performances graphiques et des animations.
- os_signpost — API pour ajouter manuellement des marqueurs dans le code, visibles ensuite dans Instruments.
Lancer le profilage est simple : sélectionnez le schéma (Scheme) dans Xcode, appuyez sur Cmd + I (Product → Profile), puis choisissez le modèle souhaité dans Instruments.
1.1. Premier lancement : Time Profiler
Supposons que vous ayez une application qui traite lentement une liste de 10 000 éléments. Lancez Time Profiler et exécutez le scénario. Après quelques secondes, vous verrez une pile d'appels triée par temps. Voici à quoi cela ressemble dans le code :
func processLargeArray() { let data = (0..<10000).map { $0 } let result = data.filter { $0 % 2 == 0 }.map { $0 * 2 } print(result.count)}Time Profiler montrera que filter et map prennent la majeure partie du temps. Mais c'est attendu. Et si le problème est ailleurs ? Par exemple, dans l'appel fréquent d'une fonction coûteuse à l'intérieur d'une boucle.
2. Exemple pratique : optimisation du travail avec Core Data
Un des problèmes courants sous iOS est la lenteur des requêtes à Core Data. Prenons un exemple : le chargement de 5000 objets avec filtrage par nom.
func fetchUsers(with name: String) -> [User] { let request = User.fetchRequest() request.predicate = NSPredicate(format: "name == %@", name) request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)] return (try? context.fetch(request)) ?? []}En lançant Time Profiler, vous pouvez constater que le fetch prend 200 ms — c'est beaucoup. Mais pourquoi ? Peut-être qu'un index sur le champ name n'a pas été créé. Dans Xcode, ajoutez l'index dans le modèle de données :
- Ouvrez le fichier .xcdatamodeld.
- Sélectionnez l'entité
User. - Dans l'inspecteur de données (Data Model Inspector), ajoutez
namedans la section Indexes.
Après cela, un nouveau profil montrera une réduction du temps à 20–30 ms. Une différence de 10 fois !
2.1. Utilisation de os_signpost pour le marquage manuel
Parfois, les outils standards ne fournissent pas le niveau de détail nécessaire. C'est là que os_signpost vient à la rescousse. Il permet de marquer manuellement le début et la fin de la section de code qui vous intéresse, puis de voir ces marqueurs dans Instruments.