Introduction
La performance des applications mobiles et desktop est un facteur clé influençant l'expérience utilisateur. Les utilisateurs attendent des applications qu'elles s'exécutent rapidement, de manière fluide et sans délais. Pour les développeurs Swift créant des applications pour l'écosystème Apple (iOS, macOS, watchOS, tvOS), l'optimisation des performances devient non seulement souhaitable mais une tâche obligatoire. Dans cet article, nous allons examiner les principales méthodes d'optimisation des performances des applications Swift, de la gestion de la mémoire au travail efficace avec le multithreading. Vous apprendrez comment éviter les erreurs courantes et rendre votre application aussi rapide que possible.
1. Gestion de la mémoire et ARC
Swift utilise le Comptage Automatique de Références (ARC) pour la gestion de la mémoire. Cependant, une mauvaise utilisation d'ARC peut entraîner des fuites mémoire et une réduction des performances. Le problème principal est les cycles de rétention.
1.1. Éviter les Cycles de Rétention
Les cycles de rétention se produisent lorsque deux objets se référencent mutuellement et qu'ARC ne peut pas libérer leur mémoire. Utilisez weak ou unowned pour rompre le cycle.
class Person { let name: String var apartment: Apartment? init(name: String) { self.name = name } deinit { print("\\(name) désalloué") }}
class Apartment { let unit: String weak var tenant: Person? // weak empêche un cycle de rétention init(unit: String) { self.unit = unit } deinit { print("Appartement \\(unit) désalloué") }}
var john: Person? = Person(name: "John")var unit4A: Apartment? = Apartment(unit: "4A")john?.apartment = unit4Aunit4A?.tenant = johnjohn = nilunit4A = nil// Les deux objets seront désalloués1.2. Utiliser les Types Valeur (Structs) au Lieu des Types Référence (Classes)
Les structs sont stockées sur la pile, ce qui est plus rapide que le stockage sur le tas pour les classes. Utilisez des structs pour les données petites et immuables.
struct Point { var x: Double var y: Double}
class PointClass { var x: Double var y: Double init(x: Double, y: Double) { self.x = x self.y = y }}
// Test de performancelet count = 1_000_000var start = CFAbsoluteTimeGetCurrent()var points = [Point](repeating: Point(x: 0, y: 0), count: count)for i in 0..<count { points[i].x = Double(i)}print("Structs : \\(CFAbsoluteTimeGetCurrent() - start) secondes")
start = CFAbsoluteTimeGetCurrent()var pointClasses = [PointClass]()for i in 0..<count { let p = PointClass(x: Double(i), y: 0) pointClasses.append(p)}print("Classes : \\(CFAbsoluteTimeGetCurrent() - start) secondes")2. Optimisation du Travail avec le Multithreading (GCD)
Grand Central Dispatch (GCD) est un outil puissant pour exécuter des tâches en parallèle. Une mauvaise utilisation peut entraîner des interblocages et une réduction des performances.
2.1. Utiliser les Files d'Attente Correctes
Pour les tâches d'arrière-plan, utilisez les files d'attente globales avec Qualité de Service (QoS) :
.userInteractive— pour les tâches nécessitant une réponse immédiate (par exemple, les animations)..userInitiated— pour les tâches initiées par l'utilisateur (par exemple, le chargement de données)..utility— pour les tâches de longue durée (par exemple, le traitement de fichiers)..background— pour les tâches qui n'affectent pas l'interface utilisateur (par exemple, la synchronisation).
DispatchQueue.global(qos: .userInitiated).async { // Tâche lourde let result = performHeavyCalculation() DispatchQueue.main.async { // Mettre à jour l'interface sur le thread principal self.updateUI(with: result) }}2.2. Éviter de Bloquer le Thread Principal
Toutes les opérations liées à l'interface utilisateur doivent être effectuées sur le thread principal. Déplacez les calculs lourds et le réseau