J'utilise Xcode 6 Beta 6.
C'est quelque chose qui me dérange depuis un certain temps maintenant, mais il atteint un point où il est à peine utilisable maintenant.
Mon projet commence à avoir une taille décente de 65 fichiers Swift et quelques fichiers Objective-C pontés (qui ne sont vraiment pas la cause du problème).
Il semble que toute légère modification d'un fichier Swift (comme l'ajout d'un simple espace blanc dans une classe à peine utilisée dans l'application) entraînera la recompilation de tous les fichiers Swift de la cible spécifiée.
Après une enquête plus approfondie, j'ai trouvé que ce qui prend à peu près 100% du temps du compilateur est la CompileSwift
phase où Xcode exécute la swiftc
commande sur tous les fichiers Swift de votre cible.
J'ai fait une enquête plus approfondie, et si je ne garde que le délégué de l'application avec un contrôleur par défaut, la compilation est très rapide, mais comme j'ajoutais de plus en plus de mes fichiers de projet, le temps de compilation commençait à devenir très lent.
Maintenant, avec seulement 65 fichiers source, il faut environ 8/10 secondes pour compiler à chaque fois. Pas très rapide du tout.
Je n'ai vu aucun article parler de ce problème, sauf celui-ci , mais c'était une ancienne version de Xcode 6. Je me demande donc si je suis le seul dans ce cas.
METTRE À JOUR
J'ai vérifié quelques projets Swift sur GitHub comme Alamofire , Euler et CryptoSwift , mais aucun d'entre eux n'avait suffisamment de fichiers Swift pour vraiment les comparer. Le seul projet que j'ai trouvé qui commençait à avoir une taille décente était SwiftHN , et même s'il n'avait qu'une douzaine de fichiers source, je pouvais toujours vérifier la même chose, un espace simple et l'ensemble du projet avait besoin d'une recompilation qui commençait à prendre un peu de temps (2/3 secondes).
Comparé au code Objective-C où l'analyseur et la compilation sont rapides, cela donne vraiment l'impression que Swift ne pourra jamais gérer de gros projets, mais dites-moi que je me trompe.
MISE À JOUR Avec Xcode 6 Beta 7
Toujours aucune amélioration. Cela commence à devenir ridicule. Avec l'absence de #import
Swift, je ne vois vraiment pas comment Apple pourra jamais optimiser cela.
MISE À JOUR Avec Xcode 6.3 et Swift 1.2
Apple a ajouté des versions incrémentielles (et de nombreuses autres optimisations du compilateur). Vous devez migrer votre code vers Swift 1.2 pour voir ces avantages, mais Apple a ajouté un outil dans Xcode 6.3 pour vous y aider:
TOUTEFOIS
Ne te réjouis pas trop vite comme moi. Le solveur de graphes qu'ils utilisent pour rendre la construction incrémentielle n'est pas encore très bien optimisé.
En effet, tout d'abord, il ne regarde pas les changements de signature de fonction, donc si vous ajoutez un espace dans le bloc d'une méthode, tous les fichiers dépendant de cette classe seront recompilés.
Deuxièmement, il semble créer l'arborescence sur la base des fichiers qui ont été recompilés même si une modification ne les affecte pas. Par exemple, si vous déplacez ces trois classes dans des fichiers différents
class FileA: NSObject {
var foo:String?
}
class FileB: NSObject {
var bar:FileA?
}
class FileC: NSObject {
var baz:FileB?
}
Maintenant, si vous modifiez FileA
, le compilateur marquera évidemment FileA
pour être recompilé. Il sera également recompilé FileB
(ce serait bien en fonction des modifications apportées à FileA
), mais aussi FileC
parce qu'il FileB
est recompilé, et c'est assez mauvais car FileC
jamais utilisé FileA
ici.
J'espère donc qu'ils amélioreront ce solveur d'arbre de dépendance ... J'ai ouvert un radar avec cet exemple de code.
MISE À JOUR Avec Xcode 7 beta 5 et Swift 2.0
Hier, Apple a publié la version bêta 5 et à l'intérieur des notes de version, nous pouvions voir:
Swift Language & Compiler • Constructions incrémentielles: changer uniquement le corps d'une fonction ne devrait plus entraîner la reconstruction des fichiers dépendants. (15352929)
Je l'ai essayé et je dois dire que ça fonctionne vraiment (vraiment!) Bien maintenant. Ils ont grandement optimisé les versions incrémentielles de Swift.
Je vous recommande fortement de créer une swift2.0
branche et de maintenir votre code à jour à l'aide de XCode 7 beta 5. Vous serez satisfait des améliorations du compilateur (mais je dirais que l'état global de XCode 7 est toujours lent et bogué)
MISE À JOUR Avec Xcode 8.2
Cela fait un moment depuis ma dernière mise à jour sur ce problème alors le voici.
Notre application compte maintenant environ 20 000 lignes de code Swift presque exclusivement, ce qui est décent mais pas exceptionnel. Il a subi une migration rapide 2 et plus rapide que 3. Il faut environ 5 / 6m pour compiler sur un Macbook pro mi-2014 (Intel Core i7 2,5 GHz), ce qui est correct sur une version propre.
Cependant, la construction incrémentielle est toujours une blague malgré Apple affirmant que:
Xcode ne reconstruira pas une cible entière lorsque seuls de petits changements se sont produits. (28892475)
Évidemment, je pense que beaucoup d'entre nous ont juste ri après avoir vérifié ce non-sens (l'ajout d'une propriété privée (privée!) À n'importe quel fichier de mon projet recompilera le tout ...)
Je voudrais vous signaler ce fil sur les forums de développeurs Apple qui contient de plus amples informations sur le problème (ainsi que la communication appréciée des développeurs Apple à ce sujet de temps en temps)
Fondamentalement, les gens ont trouvé quelques choses pour essayer d'améliorer la construction incrémentielle:
- Ajouter un
HEADER_MAP_USES_VFS
paramètre de projet défini surtrue
- Désactiver
Find implicit dependencies
de votre schéma - Créez un nouveau projet et déplacez votre hiérarchie de fichiers vers le nouveau.
J'essaierai la solution 3 mais la solution 1/2 n'a pas fonctionné pour nous.
Ce qui est ironiquement drôle dans toute cette situation, c'est qu'en regardant le premier post sur ce problème, nous utilisions Xcode 6 avec je crois que le code swift 1 ou swift 1.1 lorsque nous avons atteint la première lenteur des compilations et maintenant environ deux ans plus tard malgré les améliorations réelles d'Apple le la situation est aussi mauvaise qu'elle l'était avec Xcode 6. Quelle ironie.
Je regrette vraiment d'avoir choisi Swift plutôt que Obj / C pour notre projet en raison de la frustration quotidienne que cela implique. (Je passe même à AppCode mais c'est une autre histoire)
Quoi qu'il en soit, je vois que ce message SO a 32k + vues et 143 ups à ce jour, donc je suppose que je ne suis pas le seul. Accrochez-vous les gars malgré le pessimisme de cette situation, il pourrait y avoir de la lumière au bout du tunnel.
Si vous avez le temps (et le courage!), Je suppose qu'Apple se réjouit du radar à ce sujet.
Jusqu'à la prochaine fois! À votre santé
MISE À JOUR Avec Xcode 9
Trébuchez sur cela aujourd'hui. Xcode a discrètement introduit un nouveau système de construction pour améliorer les performances horribles actuelles. Vous devez l'activer via les paramètres de l'espace de travail.
J'ai déjà essayé, mais je mettrai à jour ce message une fois terminé. Cela semble prometteur.
Réponses:
Eh bien, il s'est avéré que Rob Napier avait raison. C'était un seul fichier (en fait une seule méthode) qui faisait que le compilateur devenait berzek.
Maintenant, ne vous méprenez pas. Swift recompile tous vos fichiers à chaque fois, mais la grande chose maintenant, c'est qu'Apple a ajouté des commentaires de compilation en temps réel sur les fichiers qu'il compile, donc Xcode 6 GM montre maintenant quels fichiers Swift sont en cours de compilation et l'état de la compilation en temps réel comme vous pouvez le voir sur cette capture d'écran:
Cela est donc très pratique pour savoir lequel de vos fichiers prend si longtemps. Dans mon cas, c'était ce morceau de code:
car la propriété
title
était de typevar title:String?
et nonNSString
. Le compilateur devenait fou en l'ajoutant auNSMutableDictionary
.Le changer en:
fait passer la compilation de 10/15 secondes (peut-être même plus) à une seule seconde ... incroyable.
la source
Nous avons essayé pas mal de choses pour lutter contre cela, car nous avons environ 100 000 lignes de code Swift et 300 000 lignes de code ObjC.
Notre première étape a été d'optimiser toutes les fonctions en fonction de la sortie des temps de compilation des fonctions (par exemple, comme décrit ici https://thatthinginswift.com/debug-long-compile-times-swift/ )
Ensuite, nous avons écrit un script pour fusionner tous les fichiers rapides en un seul fichier, cela brise les niveaux d'accès mais cela a porté notre temps de compilation de 5-6 minutes à ~ 1 minute.
Ceci est maintenant disparu car nous avons interrogé Apple à ce sujet et ils nous ont conseillé de faire ce qui suit:
'Fast, Whole Module Optimization'
'-Onone'
Lorsque ces indicateurs sont définis, le compilateur compile tous les fichiers Swift en une seule étape. Nous avons constaté que notre script de fusion est beaucoup plus rapide que la compilation de fichiers individuellement. Cependant, sans le '
-Onone'
override ' , il optimisera également l'ensemble du module, ce qui est plus lent. Lorsque nous définissons l''-Onone'
indicateur dans les autres indicateurs Swift, cela arrête l'optimisation, mais il ne cesse pas de compiler tous les fichiers Swift en une seule étape.Pour plus d'informations sur l'optimisation du module entier, consultez le blog d'Apple ici - https://swift.org/blog/whole-module-optimizations/
Nous avons constaté que ces paramètres permettent à notre code Swift de compiler en 30 secondes :-) Je n'ai aucune preuve de la façon dont cela fonctionnerait sur d'autres projets, mais je suggère de faire un essai si les temps de compilation Swift sont toujours un problème pour vous.
Remarque pour vos builds App Store, vous devez laisser le
'-Onone'
drapeau désactivé, car l'optimisation est recommandée pour les builds de production.la source
-Onone
. Nous ne pouvons pas utiliser l'optimisation de module entier pour l'instant car cela fait planter le compilateur ... Mais vos conseils donnent presque 10 fois plus de vitesse à notre build. Sur MacBook Air (annuel 2013), la durée de construction était d'environ 8 minutes, il en est maintenant à environ 1 minute et demie de ce temps, il passe entre les cibles (nous avons des applications, des extensions et quelques cadres internes) et compile des storyboards-Onone
aide pour réduire les temps de construction. Merci beaucoup mon pote!Cela a probablement peu à voir avec la taille de votre projet. Il s'agit probablement d'un morceau de code spécifique, peut-être même d'une seule ligne. Vous pouvez tester cela en essayant de compiler un fichier à la fois plutôt que l'ensemble du projet. Ou essayez de regarder les journaux de construction pour voir quel fichier prend si longtemps.
À titre d'exemple des types de code qui peuvent causer des problèmes, cet essentiel de 38 lignes prend plus d'une minute à compiler en version bêta7. Tout cela est causé par ce seul bloc:
Simplifiez cela par juste une ligne ou deux et il se compile presque instantanément. Le problème est que quelque chose provoque une croissance exponentielle (peut-être une croissance factorielle) dans le compilateur. Évidemment, ce n'est pas idéal, et si vous pouvez isoler de telles situations, vous devriez ouvrir des radars pour aider à résoudre ces problèmes.
la source
CompileSwift
phase. Il prend tous les fichiers rapides même si un seul a été modifié. Donc, si c'est un fichier qui prend du temps (ce dont je doute fortement), le compilateur ne vous dira jamais de quel fichier il s'agit.swiftc
pour voir combien de temps ils prennent.Si vous essayez d'identifier des fichiers spécifiques qui ralentissent votre temps de compilation, vous pouvez essayer de le compiler à partir de votre ligne de commande via xctool qui vous donnera des temps de compilation fichier par fichier.
La chose à noter est que, par défaut, il crée 2 fichiers simultanément pour chaque cœur de CPU, et ne vous donnera pas le temps écoulé "net", mais le temps "utilisateur" absolu. De cette façon, tous les timings se répartissent entre les fichiers parallélisés et se ressemblent beaucoup.
Pour résoudre ce problème, définissez l'
-jobs
indicateur sur 1 , afin qu'il ne parallélise pas les générations de fichiers. Cela prendra plus de temps, mais à la fin vous aurez des temps de compilation "nets" que vous pourrez comparer fichier par fichier.Voici un exemple de commande qui devrait faire l'affaire:
xctool -workspace <your_workspace> -scheme <your_scheme> -jobs 1 build
Le résultat de la phase "Compiler des fichiers Swift" serait quelque chose comme:
À partir de cette sortie, vous pouvez identifier rapidement les fichiers dont la compilation prend plus de temps que d'autres. De plus, vous pouvez déterminer avec une grande précision si vos refactorings (transtypages explicites, indices de type, etc ...) réduisent ou non les temps de compilation pour des fichiers spécifiques.
REMARQUE: techniquement, vous pouvez également le faire avec
xcodebuild
mais la sortie est incroyablement verbeuse et difficile à consommer.la source
Swift Compiler
→Optimization Level
pourFast, Whole Module Optimization [-O -whole-module-optimization]
Dans mon cas, Xcode 7 n'a fait aucune différence. J'ai eu plusieurs fonctions nécessitant plusieurs secondes pour compiler.
Exemple
Après avoir déballé les options, le temps de construction a chuté de 99,4% .
Voir plus d'exemples dans cet article et cet article .
Générer un analyseur de temps pour Xcode
J'ai développé un plug-in Xcode qui peut être utile pour quiconque rencontre ces problèmes.
Il semble y avoir des améliorations dans Swift 3, donc nous espérons que notre code Swift se compilera plus rapidement.
la source
Nous ne pouvons probablement pas réparer le compilateur Swift, mais quelque chose que nous pouvons corriger est notre code!
Il y a une option cachée dans le compilateur rapide qui imprime les intervalles de temps précis que le compilateur prend pour compiler chaque fonction:
-Xfrontend -debug-time-function-bodies
. Cela nous permet de trouver des goulots d'étranglement dans notre code et d'améliorer considérablement le temps de compilation.Exécutez simplement les éléments suivants dans le terminal et analysez les résultats:
Génial Brian Irace a écrit un article brillant à ce sujet. Profilage de votre temps de compilation Swift .
la source
alias grep='noglob grep'
premier, sinon le grep ne fonctionnera pasLa solution est de lancer.
J'avais une vaste gamme de tonnes de dictionnaires, comme ceci:
Il a fallu environ 40 minutes pour le compiler. Jusqu'à ce que je lance les dictionnaires comme ceci:
Cela a fonctionné pour presque tous les autres problèmes que j'ai rencontrés concernant les types de données que j'ai codés en dur dans mon application.
la source
Une chose à noter est que le moteur d'inférence de type Swift peut être très lent avec les types imbriqués. Vous pouvez avoir une idée générale de ce qui cause la lenteur en regardant le journal de construction des unités de compilation individuelles qui prennent beaucoup de temps, puis en copiant et en collant la commande complète générée par Xcode dans une fenêtre de terminal, puis en appuyant sur CTRL- \ pour obtenir quelques diagnostics. Jetez un œil à http://blog.impathic.com/post/99647568844/debugging-slow-swift-compile-times pour un exemple complet.
la source
Assurez-vous également que lors de la compilation pour le débogage (Swift ou Objective-C), vous définissez sur Build Active Architecture uniquement:
la source
Étant donné que tout cela est en version bêta et que le compilateur Swift n'est pas ouvert (du moins à ce jour), je suppose qu'il n'y a pas de vraie réponse à votre question.
Tout d'abord, comparer Objective-C au compilateur Swift est en quelque sorte cruel. Swift est toujours en version bêta, et je suis sûr qu'Apple travaille à fournir des fonctionnalités et à corriger les bugs, plus qu'à fournir une vitesse fulgurante (vous ne commencez pas à construire une maison en achetant les meubles). Je suppose qu'Apple optimisera le compilateur en temps voulu.
Si, pour une raison quelconque, tous les fichiers source doivent être compilés complètement, une option peut être de créer des modules / bibliothèques séparés. Mais cette option n'est pas encore possible, car Swift ne peut pas autoriser les bibliothèques tant que la langue n'est pas stable.
Je suppose qu'ils optimiseront le compilateur. Pour la même raison que nous ne pouvons pas créer de modules précompilés, il se pourrait bien que le compilateur ait besoin de tout compiler à partir de zéro. Mais une fois que le langage aura atteint une version stable et que le format des binaires ne changera plus, nous pourrons créer nos bibliothèques, et peut-être (?) Le compilateur pourra également optimiser son travail.
Mais devinez, car Apple seul le sait ...
la source
Pour Xcode 8, accédez aux paramètres du projet, puis à Éditeur> Ajouter un paramètre de génération> Ajouter un paramètre défini par l'utilisateur, puis ajoutez les éléments suivants:
L'ajout de cet indicateur a fait passer miraculeusement nos temps de compilation de construction propre de 7 minutes à 65 secondes pour un projet rapide 40KLOC. Peut également confirmer que 2 amis ont vu des améliorations similaires sur des projets d'entreprise.
Je peux seulement supposer que c'est une sorte de bogue dans Xcode 8.0
EDIT: Cela ne semble plus fonctionner dans Xcode 8.3 pour certaines personnes.
la source
Malheureusement, le compilateur Swift n'est toujours pas optimisé pour une compilation rapide et incrémentielle (à partir de Xcode 6.3 beta). Pendant ce temps, vous pouvez utiliser certaines des techniques suivantes pour améliorer le temps de compilation de Swift:
Divisez l'application en cadres pour réduire l'impact de la recompilation. Mais sachez que vous devez éviter les dépendances cycliques dans votre application. Pour plus d'informations sur ce sujet, consultez cet article: http://bits.citrusbyte.com/improving-swift-compile-time/
Utilisez Swift pour les parties de votre projet qui sont assez stables et ne changent pas souvent. Pour d'autres zones où vous devez changer très souvent ou des zones qui nécessitent beaucoup d'itérations de compilation / exécution pour être complètes (presque toutes les choses liées à l'interface utilisateur), mieux utiliser Objective-C avec une approche mix-and-match.
Essayez l'injection de code d'exécution avec 'Injection for Xcode'
Utilisez la méthode roopc: http://roopc.net/posts/2014/speeding-up-swift-builds/
Soulagez le moteur d'inférence de type rapide en donnant des indices avec des transtypages explicites.
la source
La construction de tableaux et de dictionnaires rapides semble être une cause assez populaire pour cela (spécialement pour vous qui venez d'un arrière-plan Ruby ), c'est-à-dire,
sera probablement la cause où cela devrait le corriger:
la source
Pour le débogage et les tests, assurez-vous d'utiliser les paramètres suivants pour réduire le temps de compilation d'environ 20 minutes à moins de 2 minutes,
J'ai perdu d'innombrables heures à attendre la construction du projet pour me rendre compte que je devais faire ce petit changement et que j'ai dû attendre encore 30 minutes pour le tester. Ce sont les paramètres qui ont fonctionné pour moi. (J'expérimente toujours avec les paramètres)
Mais, assurez-vous au moins de définir "DWARF avec dSYM" (si vous voulez surveiller votre application) et de créer une architecture active sur "NON" pour la publication / l'archivage à pousser vers iTunes Connect (je me souviens avoir perdu quelques heures ici aussi).
la source
Set Build for Active Architecture: YES
m'a donné une réduction d'environ 45% du temps de compilation. Grand merci.Le compilateur passe beaucoup de temps à déduire et à vérifier les types. L'ajout d'annotations de type aide donc beaucoup le compilateur.
Si vous avez beaucoup d'appels de fonctions en chaîne comme
Ensuite, le compilateur prend un certain temps pour déterminer quel
sum
devrait être le type de . L'ajout du type aide. Ce qui aide également, c'est de tirer les étapes intermittentes dans des variables distinctes.Surtout pour les types numériques
CGFloat
,Int
cela peut beaucoup aider. Un nombre littéral comme2
peut représenter de nombreux types numériques différents. Le compilateur doit donc déterminer à partir du contexte de quel il s'agit.Les fonctions dont la recherche prend beaucoup de temps
+
doivent également être évitées. L'utilisation de plusieurs+
pour concaténer plusieurs tableaux est lente car le compilateur doit déterminer quelle implémentation de+
doit être appelée pour chacun+
. Utilisez donc unvar a: [Foo]
avec à laappend()
place si possible.Vous pouvez ajouter un avertissement pour détecter les fonctions qui sont lentes à compiler dans Xcode .
Dans les paramètres de construction de votre cible, recherchez les autres drapeaux Swift et ajoutez
-Xfrontend -warn-long-function-bodies=100
pour avertir pour chaque fonction qui prend plus de 100 ms à compiler.
la source
Pour les projets qui se mélangent Objective-C et le code Swift, nous pouvons mettre
-enable-bridging-pch
enOther Swift Flags
. Avec cela, l'en-tête de pontage n'est analysé qu'une seule fois et le résultat (un fichier «en-tête précompilé» ou «PCH» temporaire) est mis en cache et réutilisé dans tous les fichiers Swift de la cible. Apple a affirmé qu'il réduit le temps de construction de 30%. Lien de référence:REMARQUE: cela ne fonctionne que pour Swift 3.1 et supérieur.
la source
Le redémarrage de mon Mac a fait des merveilles pour ce problème. Je suis passé de versions de 15 minutes à des versions de 30 secondes simplement en redémarrant.
la source
Le temps de compilation rapide a été amélioré dans le nouveau Xcode 6.3
la source
Voici un autre cas qui peut provoquer des ralentissements massifs avec l'inférence de type. Opérateurs coalescents .
Changer les lignes comme:
à
aidé à porter mon temps de compilation de 70 à 13
la source
Rien n'a fonctionné pour moi dans Xcode 6.3.1 - lorsque j'ai ajouté environ 100 fichiers Swift Xcode accroché au hasard sur la construction et / ou l'indexation. J'ai essayé une option modulaire sans succès.
L'installation et l'utilisation de Xcode 6.4 Beta ont réellement fonctionné pour moi.
la source
Cela a fonctionné comme par magie pour moi - Speed Up Swift Compilation . Il a réduit le temps de compilation à 3 minutes au lieu de 10 minutes.
Il dit que vous devez mettre le
Whole Module Optimization
tout en ajoutant-Onone
dansOther Swift Flags
.J'utilise
Swift 3
surXcode 8.3
/Xcode 8.2
.la source
Le mélange du littéral entier et du littéral flottant dans une expression entraîne également une longue durée de compilation.
Beaucoup d'expressions de compilation de 1000 + ms sont réduites à 10 ~ 100 ms après avoir mis un
.0
littéral après entier.la source