У нас была такая же проблема, и мы ее исправили. Дважды.
Инкрементная сборка (то же строение):
до: ~ 10м после: ~ 35с
КАК?
Давайте начнем с нашего опыта в первую очередь. У нас был крупный проект Swift / Obj-C, и это было главной заботой: время сборки было медленным, и вам пришлось создавать новый проект для реализации новой функции (буквально). Бонусные баллы за неработающую подсветку синтаксиса.
теория
Чтобы действительно это исправить, вы должны по- настоящему понять, как работает система сборки. Например, давайте попробуем этот фрагмент кода:
import FacebookSDK
import RxSwift
import PinLayout
и представьте, что вы используете все эти операции импорта в своем файле. А также этот файл зависит от другого файла, который зависит от других библиотек, которые в свою очередь используют другие библиотеки и т. Д.
Таким образом, чтобы скомпилировать ваш файл, XCode должен скомпилировать каждую упомянутую вами библиотеку и каждый файл, от которого он зависит, поэтому, если вы измените один из «основных» файлов, XCode должен перестроить буквально весь проект.
Сборка Xcode является многопоточной , но состоит из множества однопоточных деревьев .
Таким образом, на первом шаге каждой инкрементной сборки XCode решает, какие файлы необходимо перекомпилировать, и создает дерево AST . Если вы изменяете файл, который действует как « надежный » для других файлов, то каждый другой файл, который действует как « зависимый », должен быть перекомпилирован.
Поэтому первый совет - снизить сцепление . Части вашего проекта должны быть независимы друг от друга.
Obj-C / Swift Bridge
Проблема с этими деревьями, если вы используете мост Obj-C / Swift, Xcode должен пройти больше фаз, чем обычно:
Безупречный мир:
- Создает код Obj-C
- Построить код Swift
Obj-C / Swift Bridge:
- [REPEATABLE STEP] Сборка кода Swift, необходимого для компиляции кода Obj-C
- [REPEATABLE STEP] Сборка кода Obj-C, необходимого для компиляции кода Swift
- Повторяйте 1 и 2, пока у вас не останется только надежный код Swift & Obj-C
- Построить код Obj-C
- Построить код Swift
Так что если вы что-то измените с шага 1 или 2, у вас возникнут проблемы. Лучшее решение - минимизировать Obj-C / Swift Bridge (и удалить его из вашего проекта).
Если у вас нет моста Obj-C / Swift, это здорово, и вы можете перейти к следующему шагу:
Swift Package Manager
Пора переходить на SwiftPM (или, по крайней мере, лучше настраивать свои Cocoapods).
Дело в том, что большинство фреймворков с конфигурацией по умолчанию Cocoapods тянут за собой множество вещей, которые вам не нужны.
Чтобы проверить это, создайте пустой проект с одной зависимостью, например PinLayout, и попробуйте написать этот код с Cocoapods (конфигурация по умолчанию) и SwiftPM.
import PinLayout
final class TestViewController: UIViewController {
}
Спойлер: Cocoapods скомпилирует этот код, потому что Cocoapods будет импортировать КАЖДЫЙ ИМПОРТ PinLayout (включая UIKit), а SwiftPM - нет, потому что SwiftPM импортирует фреймворки атомарно.
Грязный хак
Вы помните, что сборка Xcode является многопоточной?
Что ж, вы можете злоупотребить этим, если вам удастся разделить ваш проект на множество независимых частей и импортировать их все как независимые фреймворки в ваш проект. Это снижает связь, и это было фактически первое решение, которое мы использовали, но на самом деле оно не было очень эффективным, потому что мы могли только сократить время инкрементной сборки до ~ 4-5 м, что НИЧЕГО по сравнению с первым методом.