Vuncloud Блог
← К полевым заметкам

Почему iOS CI в GitHub Actions такой медленный? Кэш CocoaPods, SPM и DerivedData (2026)

Полевые заметки · Кэш CocoaPods / SPM / DerivedData в GitHub Actions · Примеры workflow ·~12 мин

Оптимизация кэша iOS CI GitHub Actions: CocoaPods SPM DerivedData медленные сборки Xcode
Главное сразу

Когда iOS CI в GitHub Actions кажется медленным, дело редко в CPU — чаще в отсутствии кэша или неверных ключах, в трёх местах:

  • CocoaPods: нет кэша Pods/ → каждый run повторяет pod install
  • Swift Package Manager (SPM): граф зависимостей пересобирается; .build стирается на каждом job
  • Xcode DerivedData: cold build → полная компиляция Swift и пересборка модулей

Правильно настроив кэш CocoaPods в GitHub Actions, кэш SPM и кэш DerivedData, warm build часто ускоряется на 30 %–60 % (сравнение Shadow в waterfall-разборе).

30–60%
типичное сокращение warm build
3
CocoaPods · SPM · DerivedData
1–5 мин
обычная экономия на слой (только кэш)

1. Почему iOS CI в GitHub Actions тормозит

Первый вопрос в команде: «macos-latest слабый?» «Пора на M4 или мощнее?»

В реальных случаях замедления Xcode CI узкое место редко — CPU. Это три скрытые затраты:

  1. Повторное разрешение зависимостей (CocoaPods / SPM)
  2. Cold start DerivedData (полная перекомпиляция)
  3. Промахи actions/cache — каждый run как первый build

GitHub Actions усиливает эффект: runner'ы эфемерные (чистый диск на job), кэш сам не «прилипает», multi-branch / multi-job портят ключи. Если ищете почему один и тот же коммит то быстро, то медленно собирается, сначала разделите cold и warm — затем настройте кэш по этой заметке.

2. Куда реально уходит время iOS CI

2.1 CocoaPods (кэш Pods)

Типичная cold-стоимость: pod install около 3–8 минут.

Причина: каждый CI-run снова запускает pod install — resolve, download, integrate с нуля.

Исправление: кэшировать Pods/ через actions/cache; key = хэш Podfile.lock + github.ref + arm64. В CI — pod install --deployment.

2.2 Swift Package Manager (SPM)

Типичная стоимость: разрешение графа пакетов 1–5 минут.

Причина: переразрешение каждый run; .build удалён; Package.resolved не в cache key.

Исправление: кэшировать ~/Library/Caches/org.swift.swiftpm и .build; key включает хэш Package.resolved (см. §3.2).

2.3 Xcode DerivedData

Типичная cold-добавка: полная или почти полная компиляция 5–15 минут.

Причина: DerivedData не переиспользуется → полный Swift compile, повторная обработка assets, rebuild модулей.

Исправление: xcodebuild -derivedDataPath DerivedData и кэшировать этот путь (см. §3.3).

Команда разбирает workflow GitHub Actions: кэш CocoaPods, SPM, DerivedData и оптимизация iOS CI

3. Рабочая настройка кэша iOS CI в GitHub Actions

Для runs-on: macos-latest. Все три блока в один job, до pod install / xcodebuild (actions/cache@v4 сохраняет автоматически).

3.1 Кэш CocoaPods (обязательно)

Кэш CocoaPods · GitHub Actions
- name: Restore Pods cache
  uses: actions/cache@v4
  with:
    path: Pods
    key: pods-arm64-${{ github.ref }}-${{ hashFiles('**/Podfile.lock') }}
    restore-keys: |
      pods-arm64-${{ github.ref }}-

- name: Pod install
  run: pod install --deployment

3.2 Кэш SPM (обязательно)

Кэш SPM · iOS CI
- name: Restore SPM cache
  uses: actions/cache@v4
  with:
    path: |
      ~/Library/Caches/org.swift.swiftpm
      .build
    key: spm-arm64-${{ github.ref }}-${{ hashFiles('**/Package.resolved') }}
    restore-keys: |
      spm-arm64-${{ github.ref }}-

3.3 Кэш DerivedData (высокий impact)

Кэш DerivedData · xcodebuild
- name: Restore DerivedData cache
  uses: actions/cache@v4
  with:
    path: DerivedData
    key: dd-arm64-${{ github.ref }}-${{ hashFiles('**/Podfile.lock') }}
    restore-keys: |
      dd-arm64-${{ github.ref }}-

- name: Build iOS
  run: xcodebuild -scheme MyApp -derivedDataPath DerivedData ...

Перед сравнением времени шагов дождитесь Cache hit occurred в логах. При miss сначала исправьте key и path — не спешите винить версию Xcode.

4. Проектирование cache key (не пропускайте)

Многие усилия по оптимизации iOS CI ломаются на ключах, а не на runner'ах.

✔ Обязательно ❌ Типичные ошибки
Архитектура (arm64) Нет split arm64/x86 — сменили runner, всё miss
Ветка (github.ref) Только lockfile — DerivedData смешивается между ветками
Хэш lockfile restore-keys слишком широкие (напр. только dd-) → ложный hit
Fallback restore-keys

При смене lockfile префикс вроде dd-arm64-${{ github.ref }}- может частично переиспользовать кэш. Несколько scheme? Добавьте ${{ matrix.scheme }} в key. Параллельные jobs на одном runner не должны делить один root DerivedData — изолируйте подкаталогами ${{ github.run_id }}.

5. Self-hosted / Cloud Mac (продвинутый уровень)

На Mac mini или Cloud Mac как self-hosted runner вы не ограничены actions/cache — диск сохраняется, warm build стабильнее:

  • Фиксированный путь DerivedData
  • Фиксированный каталог Pods
  • Warm-кэш на диске (экономит 30–90 с upload/download на job)
Self-hosted · фиксированные пути
export DERIVED_DATA=/Volumes/Data/DerivedData/App-${{ github.run_id }}
export PODS_ROOT=/Volumes/Data/Pods/${{ github.ref_name }}

Полный пример job и диск данных 1 ТБ: workflow ниже и FAQ подключения CI/CD.

Self-hosted · фиксированные DerivedData + Pods
env:
  DERIVED_DATA: /Volumes/Data/DerivedData/App-${{ github.run_id }}
  PODS_ROOT: /Volumes/Data/Pods/${{ github.ref_name }}

jobs:
  build:
    runs-on: [self-hosted, macos-m4-ios]
    steps:
      - uses: actions/checkout@v4
      - name: Prepare dirs
        run: mkdir -p "$DERIVED_DATA" "$PODS_ROOT"
      - name: Pod install
        run: pod install --deployment
      - name: xcodebuild
        run: xcodebuild -scheme MyApp -derivedDataPath "$DERIVED_DATA" build

6. Cache miss ≠ медленный runner (частая ошибка)

Команды часто списывают медленный iOS CI в GitHub Actions на runner или версию Xcode. Чаще:

Что видите Более вероятная причина
Build внезапно медленнее Cache miss
P95 «плавает» Cold build'ы в warm-статистике
Случайные замедления Конкуренция DerivedData между параллельными jobs
Зависимости с нуля Неверный cache key

Сочетайте с гайдом по дисперсии сборки: cold/warm → настройка кэша → затем железо (2026: почему iOS CI/CD работает на Mac mini M4).

7. Измеренные выигрыши

Только кэш, типичная экономия:

Слой Доп. время при cold miss После настройки кэша
CocoaPods 3–8 мин warm часто <30 с–3 мин
SPM 1–5 мин resolve заметно короче при hit
DerivedData 5–15 мин warm в основном инкрементальная компиляция

В нашем 14-дневном Shadow-run только оптимизация кэша сократила warm wall clock примерно на −1:40. Убрали очередь и self-hosted с фиксированным диском — warm P95 14:12 → 6:05 (−57 %), см. обзор оптимизации.

8. FAQ

Почему iOS CI в GitHub Actions такой медленный?

Обычно не CPU — CocoaPods / SPM / DerivedData без кэша или с неверными ключами. Эфемерные runner'ы усиливают каждый miss.

Как кэшировать CocoaPods в GitHub Actions?

Кэшировать Pods/; key: pods-arm64-${{ github.ref }}-${{ hashFiles('**/Podfile.lock') }}. См. §3.1.

Как кэшировать SPM в iOS CI?

Кэшировать глобальный каталог swiftpm и .build; привязать key к Package.resolved. См. §3.2.

Какой путь использовать для кэша DerivedData?

path в actions/cache должен совпадать с xcodebuild -derivedDataPath; системный default не обязателен.

Кэш слишком большой?

GitHub ограничивает запись примерно 10 ГБ. Разбейте DerivedData keys по scheme или self-hosted с фиксированным диском без upload.

macos-latest vs self-hosted?

Hosted: только actions/cache, может очищаться между jobs. Self-hosted: фиксированный /Volumes/Data, стабильнее warm build. Сравнение в обзоре оптимизации.

9. Итог и связанные гайды

Максимальный ROI в оптимизации iOS CI часто даёт настройка кэшей CocoaPods, SPM и DerivedData — до смены чипа. Меняйте workflow сегодня и гоняйте тестовый PR.

Та же серия:

Нужны фиксированные пути DerivedData и Pods?

Vuncloud Cloud Mac M4 Pro с диском данных 1 ТБ — для self-hosted iOS CI: меньше перекладывания через actions/cache, стабильнее warm build.

Тарифы Cloud Mac · FAQ подключения CI/CD

Полевые заметки · iOS CI

iOS CI тормозит? Сначала эти три кэша

CocoaPods · SPM · DerivedData · примеры workflow

Водопад −1:40
Ограниченное предложение Смотреть тарифы