Catégories
Développement Application Mobile (FR) Featured-Post-Application-FR

Développement iOS : 8 erreurs fréquentes qui coûtent cher (et comment les éviter)

Auteur n°2 – Jonathan

Par Jonathan Massa
Lectures: 10

Résumé – Les décisions techniques inadaptées en développement iOS pénalisent stabilité, performance et expérience utilisateur, générant dettes techniques, retards de mise en marché et surcoûts de maintenance. Async et sync mal gérés, mises à jour UI hors main thread, conditions de course sur objets mutables, hardcoding des valeurs, switch non exhaustifs et sécurité négligée fragilisent l’application.
Solution : structurer l’architecture (async/await, DispatchQueue.main, queues sérialisées, MVVM/VIPER, XIB ou code programmatique), privilégier l’immutabilité, centraliser constantes, couvrir exhaustivement les switch, intégrer revues de code, tests et analyses de sécurité dans vos pipelines CI/CD.

L’écosystème iOS offre un cadre sécurisé et cohérent, limitant les risques de fragmentation ou de failles majeures au niveau du système. Cependant, cette sécurité de base ne protège pas contre des décisions techniques inadaptées.

La qualité d’une application iOS dépend avant tout de la rigueur de son implémentation, de l’organisation du code et du respect des bonnes pratiques Swift. Des erreurs courantes peuvent impacter la stabilité, la performance et générer une dette technique coûteuse à long terme. Ce constat touche tout autant les CTO, responsables produit et équipes de développement que la direction générale, car les conséquences se traduisent directement en retards de mise sur le marché, en dégradation de l’expérience utilisateur et en surcoûts de maintenance.

Asynchronisme et thread principal UI

Un asynchronisme mal maîtrisé perturbe la logique métier sans forcément déclencher un crash immédiat.

Exécuter du code UI hors du main thread entraîne des comportements imprévisibles et des crashs critiques.

Différence entre code synchrone et asynchrone

Le code synchrone bloque le flux d’exécution jusqu’à ce qu’une tâche soit terminée, alors que l’asynchrone permet de poursuivre le traitement tout en attendant une réponse. En Swift, closures et callbacks sont souvent utilisés pour récupérer des données en arrière-plan sans bloquer l’interface utilisateur.

Lorsqu’une requête réseau ou une lecture de fichier est lancée de manière asynchrone sans structuration adéquate, l’application peut tenter d’accéder à des données non encore chargées. Les variables restent alors vides ou contiennent des valeurs par défaut, sans qu’aucune exception ne soit déclenchée.

Cette absence de crash immédiat masque des incohérences dans le flux métier. Par exemple, l’affichage de listes restreintes ou incorrectes va dégrader l’expérience utilisateur sans que l’équipe de QA n’identifie facilement l’origine du problème.

La transition vers async/await en Swift 5.5, comme dans le cadre du développement d’applications mobile natives avec Swift, permet de réécrire plus lisiblement ce type de code, tout en conservant la non-blocking I/O. Les fonctions marquées async garantissent une synchronisation plus claire, évitant les pyramides de callbacks.

UIKit non thread-safe et mises à jour UI

UIKit n’est pas conçu pour être appelé depuis un thread autre que le main thread. Les contrôles visuels, le rendu des vues et les animations doivent impérativement passer par DispatchQueue.main.

Lorsqu’un développeur met à jour un UILabel ou un UITableView depuis un thread secondaire, l’application entre dans un état indéfini : vues figées, écrans vides ou crashs soudains sans stacktrace exploitable.

Même certaines bibliothèques tierces peuvent exécuter des callbacks hors du thread principal. Sans vérification explicite, le risque de comportements erratiques persiste, même si le composant semble fonctionner localement.

Pour chaque mise à jour UI, encapsuler les modifications dans DispatchQueue.main.async { … } garantit que le code s’exécute au bon endroit. Cette simple bonne pratique prévient une grande partie des crashs critiques en production.

Exemple d’entreprise suisse

Une PME suisse du secteur retail a déployé une application de prise de commandes qui affichait parfois des écrans vides après actualisation. En production, des crashs sporadiques étaient signalés sans trace claire de la cause.

L’analyse a révélé des callbacks réseau aboutissant hors du main thread, mettant à jour le tableau de produits directement depuis un thread de fond. À la suite d’un correctif visant à dispatcher systématiquement sur DispatchQueue.main, la stabilité de l’app est passée à 99,9 %.

Ce cas démontre que, malgré la maturité de l’écosystème Apple, une simple omission dans la gestion des threads peut entraîner des problèmes de disponibilité et générer un fort volume de tickets de support.

Concurrence, mutabilité et sécurité du code

L’introduction de threads parallèles améliore la réactivité mais peut engendrer des conditions de course destructrices.

Les objets mutables exposent les applications iOS à des bugs imprévisibles et difficiles à maintenir.

Risques liés à la concurrence et condition de course

Pour profiter de la puissance multicœur, plusieurs threads peuvent exécuter du code simultanément. Sans synchronisation, deux opérations de lecture/écriture peuvent accéder à la même ressource en parallèle.

Une condition de course survient lorsque l’ordre d’exécution n’est plus déterministe. Par exemple, deux threads qui incrémentent une même variable peuvent aboutir à un résultat erroné, sans qu’aucune exception ne soit lancée.

Les crashs liés à ce type de bug sont souvent aléatoires et difficiles à reproduire en phase de test. Leur résolution demande un audit complet du code concurrentiel, notamment via une maintenance logicielle évolutive et l’introduction de mécanismes de lock ou de queues en série.

L’utilisation de DispatchQueues sérialisées ou de DispatchSemaphore permet de garantir un accès exclusif aux ressources sensibles, évitant ainsi les corruptions de données silencieuses.

Objets mutables versus immuables

Un objet mutable peut changer d’état après sa création. Cette flexibilité est utile, mais complexifie la traçabilité des modifications et le debug des anomalies.

L’immutabilité, en revanche, consiste à recréer de nouvelles instances pour chaque modification. Cette approche facilite la prédictibilité du code et supprime les effets de bord.

Par défaut, les structures Swift sont immuables lorsqu’elles sont déclarées avec let. Lorsque la taille de l’objet reste raisonnable, privilégier cette stratégie réduit considérablement les risques de bugs en contexte multithread.

Dans les cas où la création d’instances volumineuses pénalise la performance, un compromis peut consister à isoler les composants critiques ou à recourir à des copy-on-write pour limiter les duplications coûteuses.

Exemple d’institution financière suisse

Une grande institution bancaire helvétique a constaté des écarts de calcul sur ses écrans de performance en temps réel. Certaines valeurs étaient tronquées, sans qu’aucune erreur ne remonte dans les logs.

L’audit technique a mis en lumière l’usage d’un objet mutable partagé entre plusieurs opérations asynchrones. En introduisant un modèle de données immuable pour les calculs critiques, le service est redevenu fiable.

Ce cas souligne l’importance de choix d’architecture dès la conception, car corriger ce type d’erreur en production nécessite souvent un refactoring majeur et coûteux.

Edana : partenaire digital stratégique en Suisse

Nous accompagnons les entreprises et les organisations dans leur transformation digitale

Architecture UI et anti-pattern du hardcoding

Un mauvais choix entre Storyboard et XIB peut engendrer une dette structurelle profonde.

Les valeurs en dur nuisent à la lisibilité et à la scalabilité du code UI.

Storyboard versus XIB : modularité et maintenance

Les Storyboards offrent une vue d’ensemble de l’application et sont rapides à mettre en place pour des projets de petite taille. Toutefois, leur montée en complexité rend la navigation et la collaboration plus difficiles.

Les XIB permettent de créer des composants isolés, facilement réutilisables et plus simples à tester. Ils offrent un contrôle fin sur chaque vue et facilitent l’intégration dans un workflow modulaire.

Pour une application iOS ambitieuse, orientée évolutivité et maintenance, privilégier les XIB ou une approche 100 % programmatique renforce la souplesse des évolutions futures.

Adopter un pattern MVVM ou VIPER renforce encore la séparation des responsabilités, comme dans une architecture logicielle évolutive, évitant l’enchevêtrement de la logique métier et de la présentation.

Hardcoding et manque de contexte

Inscrire des strings, couleurs ou tailles directement dans le code complique la localisation, la refonte graphique et les tests UI. Chaque modification nécessite une recherche manuelle et un risque d’omission.

Préférer des constantes nommées, regroupées dans des fichiers dédiés ou des extensions, améliore la lisibilité. Les modifications se font dans un seul lieu, avec un impact direct et contrôlé.

En centralisant ces valeurs dans des enums ou structures, il devient possible d’automatiser des vérifications de cohérence et d’intégrer une couche de validation pré-compilation.

Cet anti-pattern est souvent source de bugs lors d’évolutions rapides et génère un coût de maintenance supérieur à une mise en place négligée de constantes dès le départ.

Exemple d’entreprise industrielle suisse

Un constructeur suisse de machines-outils a développé une application de contrôle en usine. Les règles de style et les libellés étaient dispersés dans tout le code source.

Chaque évolution graphique ou chaque modification de spécification nécessitait plusieurs heures de recherche et de tests. La roadmap mobile était ralentie de plusieurs semaines par release.

Après une refonte visant à extraire toutes les valeurs en dur dans des constantes et à modulariser les vues, les délais de livraison ont chuté de 30 % et la dette technique a été fortement réduite.

Risques du default dans switch

Un cas default dans un switch peut masquer des cas non prévus, entraînant des comportements silencieux.

Les vulnérabilités de sécurité émergent lorsque la priorité est donnée au fonctionnel au détriment de la robustesse.

Pièges du default dans les switch

Utiliser default comme fallback général évite un warning au moment de la compilation, mais masque les nouvelles valeurs ajoutées à une enum. Les cas non gérés passent alors inaperçus.

En Swift, l’absence du default force le compilateur à vérifier la complétude du switch. Chaque ajout à l’enum génèrera une erreur de compilateur si le switch n’a pas été mis à jour.

Cette approche garantit une exhaustivité au moment de la compilation et réduit le risque de comportements inattendus lors de l’évolution du code.

L’utilisation conjointe de enums avec associated values renforce encore la vérification statique et incite à couvrir tous les scénarios métier.

Failles de sécurité liées au code

Les développeurs focalisés sur la livraison rapide peuvent passer outre la validation des inputs, l’accès sécurisé aux fichiers ou la protection contre les buffer overflows. Ces omissions exposent à des attaques classiques, soulignant la importance de la sensibilisation cybersécurité en amont.

Les standards OWASP Mobile Top 10 identifient les vulnérabilités fréquentes : injection de code, stockage non chiffré de données sensibles, mauvaise gestion des autorisations et des certificats SSL.

Intégrer dès le développement des outils de static analysis (SwiftLint, SonarQube) et suivre les guidelines Apple Security Hardening Framework réduit significativement l’exposition aux menaces.

La sécurité ne doit pas être un chantier post-développement, mais un processus continu intégré aux revues de code et aux pipelines CI/CD.

Optimisez la qualité et la robustesse de vos applications iOS

Éviter ces erreurs passe par une politique de développement structurée : choix d’architecture dès la genèse du projet, standards de code review, pipelines de QA et revues de sécurité. Chaque phase de votre chaîne de production contribue à la fiabilité, la maintenabilité et la performance de vos applications.

Nos experts sont à votre écoute pour définir avec pragmatisme un cadre de développement iOS robuste, adapté à votre contexte métier et évolutif. Ensemble, transformez vos choix techniques en atouts compétitifs durables.

Parler de vos enjeux avec un expert Edana

Par Jonathan

Expert Technologie

PUBLIÉ PAR

Jonathan Massa

En tant que spécialiste senior du conseil technologique, de la stratégie et de l'exécution, Jonathan conseille les entreprises et organisations sur le plan stratégique et opérationnel dans le cadre de programmes de création de valeur et de digitalisation axés sur l'innovation et la croissance. Disposant d'une forte expertise en architecture d'entreprise, il conseille nos clients sur des questions d'ingénierie logicielle et de développement informatique pour leur permettre de mobiliser les solutions réellement adaptées à leurs objectifs.

FAQ

Questions fréquentes sur le développement iOS

Comment éviter les crashs liés à des mises à jour UI hors du main thread?

Utiliser systématiquement DispatchQueue.main.async pour toute modification de l’interface garantit l’exécution sur le thread principal. Vérifiez qu’aucun callback réseau ou de tâche en arrière-plan n’effectue directement des mises à jour UI. Cette pratique simple évite la majorité des plantages et comportements indéfinis liés à UIKit non thread-safe.

En quoi l’async/await améliore-t-il la lisibilité et la fiabilité du code Swift?

Passer à async/await linéarise le flux d’exécution, remplace les pyramides de callbacks et centralise la gestion des erreurs via do/catch. Le code devient plus facile à lire et à maintenir, tout en conservant une I/O non bloquante. Cela réduit la dette technique et accélère la détection des incohérences métier.

Quelles stratégies pour prévenir les conditions de course en contexte multithread?

Privilégiez les DispatchQueues sérialisées ou les DispatchSemaphore pour synchroniser l’accès aux ressources partagées. Depuis Swift 5.5, les acteurs (actors) offrent une isolation automatique des données. Ces mécanismes assurent un accès exclusif et évitent les corruptions silenciieuses et les crashs aléatoires.

Storyboard, XIB ou code : quel choix pour une architecture évolutive?

Pour une application modulable et évolutive, adoptez une approche programmatique ou XIB pour des composants isolés. Les storyboards conviennent aux petits projets, mais deviennent difficiles à maintenir en équipe. Coupler cette méthode à MVVM ou VIPER renforce la séparation des responsabilités et facilite les évolutions futures.

Comment l’immutabilité réduit-elle les risques en contexte multithread?

Déclarez vos modèles avec let pour garantir leur état fixe après création. L’immutabilité supprime les effets de bord et facilite le debug. En cas de modifications, générez de nouvelles instances ou utilisez le copy-on-write sur les structures volumineuses. Cette discipline évite les divergences de données et les bugs intermittents.

Comment centraliser les valeurs (couleurs, textes) pour faciliter la maintenance?

Regroupez toutes les constantes dans des enums ou des structs dédiés, et référencez-les partout dans le projet. Utilisez les assets catalog pour les couleurs et Localizable.strings pour les textes. Ce niveau de centralisation accélère les modifications graphiques et linguistiques, et diminue les risques d’omissions.

Pourquoi éviter les cas default dans un switch Swift?

Sans default, le compilateur vous oblige à couvrir tous les cas d’une enum, générant une erreur lors de l’ajout de nouvelles valeurs. Cela garantit l’exhaustivité et prévient les comportements silencieux ou incohérents lors de l’évolution de la logique métier.

Quelles pratiques de sécurisation sont recommandées pour une app iOS?

Intégrez SwiftLint et des outils de static analysis dès le pipeline CI/CD. Validez systématiquement les inputs, chiffrez les données sensibles avec Keychain, et appliquez le Security Hardening Framework d’Apple. Adoptez les recommandations OWASP Mobile Top 10 pour limiter les risques d’injection, de stockage non sécurisé ou de failles SSL.

CAS CLIENTS RÉCENTS

Nous concevons des applications mobiles pour transformer les opérations ou conquérir de nouveaux marchés

Avec plus de 15 ans d’expertise, notre équipe conçoit des applications innovantes sur mesure. Elles sont pensées pour optimiser les opérations, réduire les coûts, conquérir de nouveaux marchés et offrir une expérience client enrichie.

CONTACTEZ-NOUS

Ils nous font confiance

Parlons de vous

Décrivez-nous votre projet et l’un de nos experts vous re-contactera.

ABONNEZ-VOUS

Ne manquez pas les
conseils de nos stratèges

Recevez nos insights, les dernières stratégies digitales et les best practices en matière de transformation digitale, innovation, technologie et cybersécurité.

Transformons vos défis en opportunités

Basée à Genève, l’agence Edana conçoit des solutions digitales sur-mesure pour entreprises et organisations en quête de compétitivité.

Nous combinons stratégie, conseil et excellence technologique pour transformer vos processus métier, votre expérience client et vos performances.

Discutons de vos enjeux stratégiques.

022 596 73 70

Agence Digitale Edana sur LinkedInAgence Digitale Edana sur InstagramAgence Digitale Edana sur Facebook