Mieliśmy ten sam problem i naprawiliśmy go. Dwa razy.
Kompilacja przyrostowa (ta sama maszyna do kompilacji):
przed: ~ 10 m po: ~ 35s
W JAKI SPOSÓB?
Zacznijmy od naszego doświadczenia. Mieliśmy ogromny projekt Swift / Obj-C i to był główny problem: czasy kompilacji były powolne i trzeba było stworzyć nowy projekt, aby wdrożyć nową funkcję (dosłownie). Punkty bonusowe za niedziałające podświetlanie składni.
Teoria
Aby naprawdę to naprawić, musisz naprawdę zrozumieć, jak działa system kompilacji. Na przykład spróbujmy tego fragmentu kodu:
import FacebookSDK
import RxSwift
import PinLayout
i wyobraź sobie, że używasz wszystkich tych importów w swoim pliku. A także ten plik zależy od innego pliku, który zależy od innych bibliotek, które z kolei korzystają z innych bibliotek itp.
Aby skompilować plik, Xcode musi skompilować każdą wymienioną bibliotekę i każdy plik , od którego zależy, więc jeśli zmienisz jeden z „podstawowych” plików, Xcode musi odbudować dosłownie cały projekt.
Kompilacja Xcode jest wielowątkowa , ale składa się z wielu jednowątkowych drzew .
Tak więc na pierwszym etapie każdej przyrostowej kompilacji Xcode decyduje, które pliki należy ponownie skompilować i buduje drzewo AST . Jeśli zmienisz plik, który działa jako „ niezawodny ” w stosunku do innych plików, więc każdy inny plik, który działa jako „ zależny ”, musi zostać ponownie skompilowany.
Pierwszą radą jest więc obniżenie sprzęgła . Części twojego projektu muszą być od siebie niezależne.
Most Obj-C / Swift
Problem z tymi drzewami, jeśli używasz mostu Obj-C / Swift, Xcode musi przejść więcej faz niż zwykle:
Doskonały świat:
- Buduje kod Obj-C
- Zbuduj kod Swift
Most Obj-C / Swift:
- [POWTARZALNY KROK] Zbuduj kod Swift, który jest potrzebny do kompilacji kodu Obj-C
- [POWTARZALNY KROK] Zbuduj kod Obj-C, który jest potrzebny do skompilowania kodu Swift
- Powtarzaj 1 i 2, aż pozostanie ci tylko niezawodny kod Swift i Obj-C
- Zbuduj kod Obj-C
- Zbuduj kod Swift
Więc jeśli zmienisz coś od kroku 1 lub 2, zasadniczo masz kłopoty. Najlepszym rozwiązaniem jest zminimalizowanie Obj-C / Swift Bridge (i usunięcie go z projektu).
Jeśli nie masz mostu Obj-C / Swift, to jest niesamowite i możesz przejść do następnego kroku:
Menedżer pakietów szybkich
Czas przejść do SwiftPM (lub przynajmniej lepiej skonfigurować Cocoapody).
Rzecz w tym, że większość frameworków z domyślną konfiguracją Cocoapods przeciąga wraz z sobą wiele rzeczy, których nie potrzebujesz.
Aby to przetestować, utwórz pusty projekt z tylko jedną zależnością, na przykład PinLayout, i spróbuj napisać ten kod za pomocą Cocoapods (konfiguracja domyślna) i SwiftPM.
import PinLayout
final class TestViewController: UIViewController {
}
Spoiler: Cocoapods skompilują ten kod, ponieważ Cocoapods zaimportują KAŻDY IMPORT PinLayout (w tym UIKit), a SwiftPM nie, ponieważ SwiftPM importuje struktury atomowo.
Brudny hack
Czy pamiętasz, że Xcode jest wielowątkowy?
Cóż, możesz go nadużyć, jeśli jesteś w stanie podzielić swój projekt na wiele niezależnych elementów i zaimportować je wszystkie jako niezależne ramy do projektu. Zmniejsza to sprzężenie i było to właściwie pierwsze zastosowane przez nas rozwiązanie, ale w rzeczywistości nie było bardzo skuteczne, ponieważ mogliśmy jedynie skrócić czas kompilacji do ~ 4-5 m, co nie jest NIC w porównaniu z pierwszą metodą.