Lorsque plusieurs personnes modifient simultanément un Storyboard ou un XIB, la fusion XML peut sembler réussie alors que les vrais problèmes n’apparaissent qu’au moment de l’archivage complet : objet lié supprimé, fichier d’interface impossible à compiler, format des fichiers strings de localisation endommagé ou sorties de même nom provenant de deux modules qui s’écrasent mutuellement. Plutôt que d’attendre qu’un Mac cloud sur ArmVMS signale l’erreur après une compilation complète, mieux vaut effectuer d’abord une prévalidation indépendante avec l’outil ibtool fourni par Xcode.
Définir ce qu’ibtool peut vérifier
ibtool est le compilateur en ligne de commande des ressources Interface Builder. Il peut lire séparément les fichiers .storyboard et .xib, puis signaler les problèmes de structure XML, de connexions entre objets, de certaines propriétés et les avertissements émis pendant la compilation. Ce contrôle ne nécessite généralement pas de compiler au préalable le code métier, ce qui permet de l’exécuter au début des vérifications de commit ou d’un pipeline CI.
Il ne remplace toutefois pas une compilation complète. La présence réelle des classes personnalisées, la compatibilité des types Swift, l’intégration correcte des ressources à la cible et la réussite de l’édition de liens finale doivent toujours être vérifiées avec xcodebuild. L’ordre recommandé consiste à exécuter d’abord ibtool, puis, si ce contrôle réussit, à compiler et tester le projet cible.
Considérez ibtool comme un vérificateur syntaxique et structurel des ressources d’interface, et non comme un outil de validation finale de la livraison. Sa valeur réside dans sa capacité à échouer rapidement, pas à couvrir toute la sémantique d’une compilation.
Avant de commencer, vérifiez le répertoire de développement réellement utilisé par la tâche afin d’éviter que la session interactive et l’automatisation ne sélectionnent des versions différentes de Xcode :
xcode-select -p
xcodebuild -version
xcrun --find ibtool
Si plusieurs versions de Xcode sont installées sur une même machine, évitez de modifier continuellement la sélection globale dans les tâches. Définissez explicitement DEVELOPER_DIR pour chaque tâche et utilisez la même valeur pour la prévalidation et la compilation qui suit.
Compiler en lot les Storyboards et les XIB
Le script ci-dessous recherche récursivement les fichiers d’interface du projet tout en ignorant les dépendances, les produits de compilation et les répertoires de cache. Il génère un hachage à partir du chemin relatif : même si plusieurs modules contiennent un fichier Main.storyboard, leurs sorties ne se chevaucheront pas.
#!/bin/bash
set -euo pipefail
export LANG=C
export LC_ALL=C
ROOT="${1:-$PWD}"
TMP="$(mktemp -d "${TMPDIR:-/tmp}/ibtool-check.XXXXXX")"
trap 'rm -rf "$TMP"' EXIT
status=0
while IFS= read -r -d '' file; do
rel="${file#"$ROOT"/}"
key="$(printf '%s' "$rel" | shasum -a 256 | cut -c1-12)"
log="$TMP/$key.log"
case "$file" in
*.storyboard) output="$TMP/$key.storyboardc" ;;
*.xib) output="$TMP/$key.nib" ;;
*) continue ;;
esac
printf 'Checking %s
' "$rel"
if ! xcrun ibtool \
--errors \
--warnings \
--notices \
--compile "$output" \
"$file" >"$log" 2>&1; then
cat "$log"
status=1
fi
done < <(
find "$ROOT" \
\( -path '*/Pods/*' \
-o -path '*/Carthage/*' \
-o -path '*/.build/*' \
-o -path '*/DerivedData/*' \) -prune \
-o \( -name '*.storyboard' -o -name '*.xib' \) \
-type f -print0
)
exit "$status"
L’association de -print0 et de read -d '' permet de traiter correctement les chemins contenant des espaces. Le répertoire temporaire est supprimé avec trap, de sorte qu’aucun produit compilé ne reste dans l’espace de travail. Les journaux d’échec ne sont affichés que pour les fichiers concernés, ce qui évite de noyer les logs de CI sous une multitude de messages de réussite.
Ne pas compiler directement dans le répertoire source
Un fichier .storyboardc est en réalité un répertoire, tandis qu’un .nib peut lui aussi contenir plusieurs résultats compilés. Si les sorties sont écrites à proximité des sources, elles peuvent perturber l’état Git, l’analyse des ressources et les étapes de packaging ultérieures. Tous les produits de prévalidation doivent être placés dans un répertoire temporaire propre à la tâche, puis supprimés à sa fin.
Vérifier également les ressources localisées
Les projets utilisant Base Localization conservent généralement un Storyboard de base et des fichiers .strings pour chaque langue. Le fichier d’interface peut se compiler correctement alors qu’un fichier strings reste endommagé par des guillemets, des séquences d’échappement ou des marqueurs de conflit. Commencez par en vérifier le format avec plutil :
find "$PWD" -type f \
\( -name '*.strings' -o -name '*.stringsdict' \) \
-not -path '*/Pods/*' \
-print0 |
while IFS= read -r -d '' file; do
plutil -lint "$file"
done
Pour examiner les clés traduisibles de l’interface de base, vous pouvez générer une liste temporaire :
xcrun ibtool \
--generate-strings-file /tmp/Main.generated.strings \
App/Base.lproj/Main.storyboard
plutil -lint /tmp/Main.generated.strings
N’utilisez pas le fichier généré pour écraser directement les traductions maintenues manuellement. L’ordre de génération et les commentaires peuvent varier selon la version de Xcode. Il est plus fiable d’analyser l’ensemble des clés afin de vérifier que les nouvelles clés sont bien entrées dans le processus de traduction et que les clés obsolètes ne sont pas conservées.
Transformer les diagnostics en contrôle CI maintenable
Un échec de prévalidation doit arrêter immédiatement l’étape en cours, tandis que les avertissements doivent être classés selon leur importance. Les problèmes de compatibilité de mise en page, l’absence d’étiquettes d’accessibilité et les avertissements relatifs à d’anciennes propriétés méritent d’être consignés. En revanche, les nouveaux diagnostics introduits par une version différente de Xcode ne doivent pas bloquer soudainement toutes les branches sans évaluation préalable.
| Symptôme | Cause fréquente | Traitement |
|---|---|---|
| Échec de l’analyse XML | Marqueurs de conflit de fusion ou fichier tronqué | Corriger le commit à l’origine du conflit et éviter de supprimer manuellement des nœuds inconnus |
| Sortie écrasée | Plusieurs modules contiennent des fichiers d’interface de même nom | Générer le nom de sortie à partir d’un hachage du chemin relatif |
| Impossible d’analyser le fichier de localisation | Erreur de guillemets, de points-virgules ou d’échappement | Exécuter plutil -lint sur tous les fichiers strings et stringsdict |
| Réussite locale, échec en CI | Version de Xcode ou valeur de DEVELOPER_DIR différente |
Consigner les versions dans les logs et uniformiser l’environnement des tâches |
| Nombre d’avertissements instable | Changement de version des outils ou périmètre d’analyse variable | Fixer les répertoires exclus et comparer les nouveaux avertissements |
Pour les petites modifications, le contrôle peut se limiter aux fichiers d’interface modifiés dans la branche courante. La branche principale et les tâches planifiées doivent en revanche analyser l’intégralité du dépôt. Le contrôle incrémental accélère le retour d’information, tandis que l’analyse complète détecte les omissions liées aux renommages, aux suppressions et aux changements entre modules. Aucun des deux ne doit remplacer l’autre.
Terminer la validation par une compilation complète
Après la réussite d’ibtool, exécutez au moins une compilation pour simulateur ne nécessitant pas de signature afin de vérifier que les ressources d’interface fonctionnent avec le code, l’appartenance aux cibles et les autres ressources :
: "${WORKSPACE:?Set WORKSPACE to the workspace path}"
: "${SCHEME:?Set SCHEME to the shared scheme}"
xcodebuild \
-workspace "$WORKSPACE" \
-scheme "$SCHEME" \
-destination 'generic/platform=iOS Simulator' \
CODE_SIGNING_ALLOWED=NO \
build
Le contrôle final doit confirmer que la prévalidation et la compilation complète utilisent la même version de Xcode, que les répertoires exclus par le script correspondent aux répertoires de dépendances du projet, que les produits temporaires ne peuvent pas entrer dans le dépôt et que les logs d’échec conservent les chemins relatifs d’origine. Les problèmes liés aux ressources d’interface sont ainsi détectés en quelques secondes, tandis que ceux qui nécessitent le contexte complet du projet passent ensuite à la compilation intégrale, avec une séparation plus nette des responsabilités de diagnostic.
Questions fréquentes
Le contrôle ibtool remplace-t-il une compilation Xcode complète ?
Non. Il détecte rapidement les défauts propres aux fichiers d’interface, mais xcodebuild reste nécessaire pour vérifier les types, réglages, ressources, liens et bundles finaux.
Pourquoi ne pas nommer les sorties uniquement avec le nom du fichier source ?
Plusieurs modules peuvent contenir un Main.storyboard ou un View.xib identique. Il faut conserver le chemin relatif ou en calculer une empreinte pour éviter les écrasements.
Faut-il faire échouer la CI pour chaque avertissement ibtool ?
Il vaut mieux enregistrer une base stable et bloquer uniquement les nouveaux avertissements. Les textes de diagnostic peuvent évoluer avec la version de Xcode.
Choisissez un nœud physique Apple Silicon dédié pour votre prochaine compilation
Louez ArmVMS M4 ou ArmVMS M4 Pro à la journée, à la semaine, au mois ou au trimestre. Vérifiez chaque configuration, nœud et option avant de créer votre commande.