Xcode 26 компилируется слишком медленно: как ускорить удалённый Mac в 2026 году?
Побеждает диагностика по времени задач: если Xcode 26 компилируется слишком медленно, сначала зафиксируйте Build Timing Summary и журналы xcodebuild, затем исправьте зависимости, скрипты и цели проекта. Расширять удалённый Mac стоит только тогда, когда CPU, память или диск остаются узким местом после повторяемого сравнения.
Эта схема подходит независимым разработчикам, которые несколько раз в день ждут инкрементную сборку и хотят быстрее переходить от изменения к запуску. Она также нужна тем, кто выполняет Release Archive, автоматические тесты или CI на удалённом Mac. Небольшие команды, выбирающие конфигурацию Mac, получат способ проверить аппаратную причину до расходов на расширение.
Xcode 26 компилируется слишком медленно: сначала разделите задержку на этапы
Одинаковая жалоба «сборка медленная» может описывать разные процессы. Первый запуск после получения репозитория включает получение Swift Package и бинарных зависимостей. Инкрементная сборка должна использовать уже подготовленные результаты, но неверная связь Target может заставить Xcode повторно обрабатывать лишние цели. Release Archive добавляет линковку, обработку символов, подпись и сценарии публикации. Тесты включают запуск приложения и симуляторов, поэтому их общая длительность не равна времени компиляции.
Для честного сравнения зафиксируйте:
- один и тот же commit;
- одинаковые Scheme и конфигурацию Build;
- одинаковый набор Target;
- один и тот же симулятор или физическое устройство;
- одинаковое состояние зависимостей;
- отсутствие параллельных тяжёлых задач на Mac.
Apple описывает отдельные средства анализа времени сборки и рекомендации для ускорения инкрементных компиляций в документации по улучшению скорости incremental builds. Это важнее случайного сравнения «до и после очистки кэша».
В Xcode откройте отчёт сборки и включите отображение времени операций. Ищите не только общий итог, но и конкретные Swift-файлы, Target, скрипты и шаги обработки ресурсов. Для воспроизводимого журнала можно использовать командную строку:
xcodebuild \
-workspace "<WORKSPACE_PATH>" \
-scheme "<SCHEME_NAME>" \
-configuration Debug \
-destination 'platform=iOS Simulator,id=<SIMULATOR_ID>' \
clean build \
| tee "<BUILD_LOG_PATH>"
Для инкрементной проверки не запускайте clean перед каждой попыткой. Сначала выполните обычную сборку, измените небольшой участок кода, затем повторите ту же команду без очистки. Иначе проверка измерит чистую сборку, а не ежедневный цикл разработки.
Build Timing Summary показывает причину, а не только общий итог
Как в Xcode 26 увидеть длительность каждой задачи
Build Timing Summary нужен, чтобы определить, какой элемент действительно удерживает сборку. В отчёте ищите наиболее длительные операции и сопоставляйте их с изменением исходников. Если после маленького изменения снова выполняются компиляция нескольких несвязанных Target, обработка ресурсов и генерация кода, проблема находится в графе проекта или сценариях, а не обязательно в чипе.
Для дополнительной проверки сохраните журналы двух одинаковых запусков:
xcodebuild \
-project "<PROJECT_PATH>" \
-scheme "<SCHEME_NAME>" \
-configuration Debug \
-destination 'platform=iOS Simulator,id=<SIMULATOR_ID>' \
build \
| tee "<INCREMENTAL_LOG_PATH>"
Сравнивайте одинаковые типы запусков: инкрементный с инкрементным, Archive с Archive, тесты с тестами. Первый запуск нельзя использовать как эталон ежедневной работы, если он одновременно скачивает зависимости.
Почему очистка DerivedData не становится постоянным ускорением
DerivedData хранит результаты, необходимые для повторного использования при последующих сборках. Если кэш повреждён, содержит результаты после смены ветки или Xcode ведёт себя явно некорректно, очистка может помочь восстановить нормальное состояние. Но после удаления следующая компиляция снова должна построить отсутствующие артефакты.
Проверка выглядит так:
rm -rf "<DERIVED_DATA_PATH>"
xcodebuild \
-workspace "<WORKSPACE_PATH>" \
-scheme "<SCHEME_NAME>" \
-configuration Debug \
-destination 'platform=iOS Simulator,id=<SIMULATOR_ID>' \
build
Эту операцию следует считать восстановлением, а не оптимизацией. Если после очистки проблема исчезает только на один запуск, причина, вероятно, связана с кэшем, сменой ветки, зависимостью или настройками проекта. Если же очистка выполняется перед каждым тестом, теряется главное преимущество инкрементной компиляции.
Важно: не смешивайте чистую сборку и повседневную инкрементную сборку в одном показателе. Они отвечают на разные вопросы и требуют разных решений.
Что проверить в исходниках и Target
После чтения отчёта проверьте наиболее дорогие Swift-файлы и широкие зависимости между модулями. Apple отдельно рассматривает оптимизацию эффективности сборки с помощью практик кодирования. Практические направления проверки:
- слишком крупные файлы, которые меняются из-за небольшой правки;
- чрезмерно сложные выражения и вывод типов;
- публичные символы там, где достаточно внутреннего доступа;
- Target, подключённые к зависимостям без реальной необходимости;
- повторяющиеся скрипты генерации кода;
- скрипты, запускающиеся на каждом изменении вместо запуска только при изменении входных файлов;
- ресурсы, которые обрабатываются для Target, не использующего их.
После каждой правки сохраните новый Build Timing Summary. Изменение считается полезным только при одинаковом типе сборки и сопоставимом commit. Общие обещания ускорения без такой пары измерений не дают надёжной основы для покупки более мощного Mac.
Release Archive: компиляция, линковка и подпись требуют разных решений
Debug может завершаться быстро, а Release Archive — заметно дольше. Это не доказывает нехватку памяти или процессора. В Archive участвуют дополнительные Target, оптимизация, линковка, обработка dSYM, копирование ресурсов, подпись и пользовательские сценарии. Для распределения приложения Apple описывает отдельные этапы в руководстве по подготовке Beta- и релизных сборок.
Запустите повторяемый Archive с заполнителями вместо реальных путей и идентификаторов:
xcodebuild \
-workspace "<WORKSPACE_PATH>" \
-scheme "<SCHEME_NAME>" \
-configuration Release \
-destination 'generic/platform=iOS' \
-archivePath "<ARCHIVE_PATH>" \
archive
Разделите журнал на следующие группы:
- разрешение и получение зависимостей;
- компиляция исходников;
- линковка;
- обработка ресурсов и символов;
- подпись;
- пользовательские скрипты;
- экспорт или дальнейшая загрузка результата.
Если долго выполняется скрипт, его следует профилировать отдельно. Если время уходит на линковку, проверьте состав библиотек и число подключённых Target. Если Debug быстр, а Release медленный на компиляции, сравните настройки оптимизации и условную компиляцию. Сначала исправляйте повторяемую работу проекта. Только затем оценивайте аппаратную конфигурацию.
Для задач публикации полезно отделять Archive от загрузки. Медленный интернет, проверка сертификата или доступ к приватному репозиторию не являются медленной компиляцией. Сертификаты и профили также требуют отдельной проверки; смешивание этих этапов усложняет поиск причины.
Swift Package и новый удалённый Mac: восстановление зависимостей без ложного диагноза
При переносе проекта на удалённый Mac первая сборка может быть медленной из-за синхронизации репозитория, разрешения Swift Package и получения бинарных архивов. Это особенно заметно при новом арендном периоде или чистой среде CI. Apple рассматривает сборку Swift Package и приложений с такими пакетами в документации по CI-процессам.
Проверьте следующие границы:
Package.resolvedдолжен быть добавлен в репозиторий там, где проекту требуется фиксированный набор версий;- ошибка разрешения версии отличается от медленной загрузки;
- медленная загрузка отличается от медленной компиляции уже скачанных исходников;
- приватные пакеты требуют отдельно проверить токены, SSH-доступ и сетевые разрешения;
- бинарная зависимость может занимать время на получение, распаковку и проверку;
- старый кэш нельзя считать доказательством воспроизводимой сборки.
Пример запуска с явно заданным каталогом результатов:
xcodebuild \
-workspace "<WORKSPACE_PATH>" \
-scheme "<SCHEME_NAME>" \
-configuration Release \
-clonedSourcePackagesDirPath "<PACKAGE_CACHE_PATH>" \
-derivedDataPath "<DERIVED_DATA_PATH>" \
archive \
-archivePath "<ARCHIVE_PATH>"
Названия путей здесь намеренно заменены заполнителями. В реальном CI их нужно задавать через секреты и переменные среды, а не записывать в публичный репозиторий.
Если требуется сохранить кэш между запусками, зафиксируйте, что именно сохраняется: исходники пакетов, результаты компиляции или временные файлы. Кэш должен иметь понятный ключ, связанный с commit, конфигурацией и версией Xcode. Непроверяемый старый кэш иногда скрывает ошибку, которая проявится при чистом Archive.
Параллельные тесты: больше процессов не означает более быстрый результат
Как отличить тестовый цикл от компиляции приложения
Тестовый запуск может включать компиляцию тестовых Target, сборку приложения, запуск симулятора, установку приложения и выполнение сценариев. Для запуска на симуляторе или физическом устройстве используйте рекомендации Apple по запуску приложения на виртуальных и физических устройствах.
Измеряйте отдельно:
xcodebuild \
-workspace "<WORKSPACE_PATH>" \
-scheme "<SCHEME_NAME>" \
-destination 'platform=iOS Simulator,id=<SIMULATOR_ID>' \
test \
| tee "<TEST_LOG_PATH>"
Сравните время компиляции до тестов, время запуска симулятора и само выполнение тестовых наборов. Если приложение собирается быстро, но UI-тесты долго поднимают окружение, увеличение вычислительной конфигурации может не решить задержку.
Параллельный запуск создаёт дополнительные процессы, симуляторы и операции с памятью. На загруженном Mac он способен увеличить конкуренцию за CPU и диск, а также число нестабильных тестов. Поэтому сравнивайте не только итоговое время, но и количество повторных запусков, ошибок и зависаний.
Apple рекомендует организовывать тесты с учётом скорости обратной связи в руководстве по структуре тестов. Практическое разделение выглядит так:
- быстрый набор — после небольшой правки;
- расширенный набор — перед слиянием ветки;
- полный UI-набор — перед релизным Archive;
- отдельные тяжёлые тесты — в CI, а не в каждом локальном цикле.
Если увеличение параллельности сокращает время выполнения, но повышает число сбоев, настройка не является улучшением для команды. Уровень параллельности выбирается по устойчивому результату, а не по максимальному числу одновременно запущенных тестов.
Удалённый Mac: когда менять конфигурацию, а когда чинить проект
Удалённый Mac оправдан как постоянный iOS build server, когда Archive, тесты или CI должны работать независимо от ноутбука разработчика. Но он не устраняет задержки, вызванные неправильным графом Target, постоянным скачиванием зависимостей или повторным запуском скрипта. В таком случае более мощный Mac лишь быстрее выполняет лишнюю работу.
Разделяйте решения по наблюдаемым признакам:
- CPU постоянно занят во время компиляции — сравните другой процессорный профиль;
- память постоянно испытывает давление — проверяйте параллельные тесты, симуляторы и число одновременных задач;
- диск занят ожиданием — исследуйте DerivedData, распаковку пакетов, линковку и параллельные операции;
- большая часть времени уходит на сеть — проверяйте репозиторий, Swift Package и приватную аутентификацию;
- удалённая сессия тормозит, а журнал сборки нет — отделяйте задержку VNC или браузера от самой сборки.
Для оценки вариантов полезно применять условную логику:
- если долгими остаются конкретные файлы и скрипты, сначала меняйте проект;
- если только первый запуск медленный, настраивайте зависимости и кэш;
- если Archive стабильно упирается в CPU или память, тестируйте более мощную конфигурацию;
- если локальный Mac занят только в часы CI, сравните временную аренду Mac по неделям и месяцам с покупкой отдельной машины;
- если задачи требуют постоянных физических портов или локального устройства, удалённая среда может не подойти.
Подробности текущей среды можно проверить через страницу SFTPMAC с вариантами Mac. Это не заменяет тест на реальном проекте: конфигурацию следует выбирать по собственному Archive и тестовым журналам, а не по одному названию чипа.
Приёмка удалённого Mac на одном и том же проекте
Перед продлением аренды или расширением конфигурации выполните одинаковый набор задач. Не меняйте одновременно commit, Scheme, версию Xcode и параметры тестов. Для CI дополнительно сохраните логи получения зависимостей и время выполнения скриптов.
- [ ] Зафиксирован commit и проверен
Package.resolved. - [ ] Записаны отдельные результаты инкрементной сборки и чистого Archive.
- [ ] Первый запуск после восстановления зависимостей отделён от повторного.
- [ ] Build Timing Summary сохранён до изменения проекта.
- [ ] Проверены Target-зависимости и входные файлы пользовательских скриптов.
- [ ] DerivedData очищалась только как диагностическая процедура.
- [ ] Тесты разделены на быстрый, расширенный и полный наборы.
- [ ] Параллельность тестов изменялась постепенно, с фиксацией сбоев.
- [ ] Отдельно измерены CPU, давление памяти, ожидание диска и сетевые операции.
- [ ] После оптимизации выполнен повторный Archive на том же commit.
- [ ] Проверено, что результат стабилен при нескольких одинаковых запусках.
- [ ] Зафиксировано решение: правка проекта, расширение Mac или разделение задач.
Если аппаратная нагрузка не подтверждается, расширение откладывается. Если же удалённый Mac стабильно занят во время компиляции, Archive и тестов, а проектные причины исключены, имеет смысл сравнить другую конфигурацию или вынести тяжёлые задачи в отдельный CI-поток. Для сценария постоянной подписи и упаковки можно дополнительно изучить подходы к организации iOS-сервера сборки.
Текущая среда или аренда Mac: что выбрать после измерений
Локальный Mac удобен для работы с физическим устройством, быстрым интерфейсом Xcode и файлами без сетевой задержки. Но отдельная машина для CI замораживает бюджет, требует обслуживания и может простаивать вне релизных циклов. Облачная компиляция снимает часть администрирования, однако ограничивает контроль над окружением, кэшем и нестандартными скриптами.
Если текущая схема использует единственный ноутбук, у неё обычно есть три недостатка: сборка блокирует рабочее устройство, ночные задачи зависят от его состояния, а восстановление после сбоя требует ручного вмешательства. Когда сборки запускаются регулярно, настоящий удалённый Mac с root-доступом позволяет держать окружение доступным через SSH, VNC или веб-консоль и отдельно проверять Archive на том же проекте.
Для временного CI, релизной недели или проверки производительности аренда SFTPMAC может быть рациональнее немедленной покупки. Для постоянной тяжёлой нагрузки на протяжении длительного срока собственный Mac может оказаться предсказуемее по совокупной стоимости. Если же проекту нужны физические интерфейсы, локальный iPhone или минимальная задержка графического интерфейса, удалённый вариант следует рассматривать только после проверки этих ограничений.
Правильный следующий шаг — не очищать DerivedData вслепую, а перенести зафиксированный проект на удалённый Mac и повторить инкрементную сборку, Archive и тестовый набор. Если результаты подтверждают аппаратное ограничение, условия аренды SFTPMAC можно оценить по нужной продолжительности — например, для краткого эксперимента или постоянного процесса сборки.