Abbiamo avuto lo stesso problema e lo abbiamo risolto. Due volte.
Build incrementale (stessa build machine):
prima: ~ 10m dopo: ~ 35s
COME?
Cominciamo prima con la nostra esperienza. Avevamo un enorme progetto Swift / Obj-C e questa era la preoccupazione principale: i tempi di costruzione erano lenti e dovevi creare un nuovo progetto per implementare una nuova funzionalità (letteralmente). Punti bonus per l'evidenziazione della sintassi mai funzionante.
Teoria
Per risolvere veramente questo problema, devi veramente capire come funziona il sistema di compilazione. Ad esempio, proviamo questo snippet di codice:
import FacebookSDK
import RxSwift
import PinLayout
e immagina di usare tutte queste importazioni nel tuo file. E anche questo file dipende da un altro file, che dipende da altre librerie, che a loro volta usano altre librerie ecc.
Quindi per compilare il tuo file Xcode deve compilare ogni libreria che hai citato e ogni file da cui dipende, quindi se cambi uno dei file "core" Xcode deve ricostruire letteralmente l'intero progetto.
La build di Xcode è multi-thread , ma è composta da molti alberi a thread singolo .
Quindi sul primo passo di ogni build incrementale Xcode sta decidendo quali file devono essere ricompilati e costruisce un albero AST . Se si modifica un file che si comporta come " affidabile " su altri file, è necessario ricompilare ogni altro file che agisce come " dipendente ".
Quindi il primo consiglio è di abbassare l'accoppiamento . Le parti del progetto devono essere indipendenti l'una dall'altra.
Ponte Obj-C / Swift
Problema con quegli alberi se stai usando un bridge Obj-C / Swift, Xcode deve attraversare più fasi del solito:
Mondo perfetto:
- Costruisce il codice Obj-C
- Crea codice Swift
Ponte Obj-C / Swift:
- [PASSO RIPETIBILE] Crea codice Swift, necessario per compilare il codice Obj-C
- [PASSO RIPETIBILE] Crea il codice Obj-C, necessario per compilare il codice Swift
- Ripeti 1 e 2 fino a quando ti rimane solo il codice Swift & Obj-C non affidabile
- Costruisci il codice Obj-C
- Crea codice Swift
Quindi, se cambi qualcosa dal passaggio 1 o 2, sei sostanzialmente nei guai. La soluzione migliore è minimizzare Obj-C / Swift Bridge (e rimuoverlo dal progetto).
Se non hai un Obj-C / Swift Bridge, è fantastico e sei a posto per andare al passo successivo:
Swift Package Manager
È ora di passare a SwiftPM (o almeno configurare meglio i tuoi Cocoapods).
Il fatto è che la maggior parte dei framework con configurazione Cocoapods predefinita trascina con sé molte cose che non ti servono.
Per testarlo, crea un progetto vuoto con una sola dipendenza come PinLayout, ad esempio, e prova a scrivere questo codice con Cocoapods (configurazione predefinita) e SwiftPM.
import PinLayout
final class TestViewController: UIViewController {
}
Spoiler: Cocoapods compilerà questo codice, perché Cocoapods importerà OGNI IMPORTANTE di PinLayout (incluso UIKit) e SwiftPM non lo farà perché SwiftPM importa i framework atomicamente.
Hack sporco
Ricordi che Xcode build è multi-thread?
Bene, puoi abusarne, se sei in grado di dividere il tuo progetto in molti pezzi indipendenti e importarli tutti come framework indipendenti nel tuo progetto. Abbassa l'accoppiamento e questa è stata in realtà la prima soluzione che abbiamo usato, ma in realtà non era molto efficace, perché potevamo solo ridurre il tempo di costruzione incrementale a ~ 4-5 m, il che è NULLA rispetto al primo metodo.