Vuncloud Blog
← Zurück zu Cloud Lab

Warum ist GitHub Actions iOS CI so langsam? CocoaPods-, SPM- & DerivedData-Cache (2026)

Cloud Lab · CocoaPods / SPM / DerivedData in GitHub Actions cachen · Workflow-Beispiele ·~12 Min. Lesezeit

GitHub Actions iOS CI Cache: CocoaPods SPM DerivedData Xcode langsame Builds
Kurz gesagt

Wenn GitHub Actions iOS CI langsam wirkt, liegt es selten an der CPU — meist an fehlendem Cache oder falschen Cache-Keys, an drei Stellen:

  • CocoaPods: kein Pods/-Cache → jeder Lauf wiederholt pod install
  • Swift Package Manager (SPM): Abhängigkeitsgraph neu aufgelöst; .build pro Job gelöscht
  • Xcode DerivedData: Cold Builds → voller Swift-Compile und Modul-Rebuild

Wer CocoaPods-Cache auf GitHub Actions, SPM-Cache und DerivedData-Cache richtig verdrahtet, sieht warm oft 30 %–60 % weniger Wandzeit (Shadow-Vergleich in der Wasserfall-Aufschlüsselung).

30–60%
typische Reduktion warm build
3
CocoaPods · SPM · DerivedData
1–5 min
übliche Einsparung pro Schicht (nur Cache)

1. Warum GitHub Actions iOS CI zieht

Die erste Frage im Team: „Ist macos-latest zu schwach?“ „Sollen wir auf M4 oder größeres Eisen wechseln?“

In echten Xcode-CI-Verlangsamungen ist die CPU selten der Engpass. Es sind drei versteckte Kosten:

  1. Abhängigkeiten neu auflösen (CocoaPods / SPM)
  2. DerivedData Cold Starts (Voll-Recompile)
  3. actions/cache-Misses — jeder Lauf fühlt sich wie ein Erstbuild an

GitHub Actions verstärkt das: Runner sind ephemeral (saubere Platte pro Job), Cache „klebt“ nicht von allein, und Multi-Branch-/Multi-Job-Setups vermischen Keys. Wer warum derselbe Commit mal schnell, mal langsam baut sucht, trennt zuerst cold vs. warm — dann Cache nach dieser Feldnotiz.

2. Wo iOS-CI-Zeit wirklich hingeht

2.1 CocoaPods (Pods-Cache)

Typische Cold-Kosten: pod install etwa 3–8 Minuten.

Ursache: jeder CI-Lauf führt pod install neu aus — resolve, download, integrate von vorn.

Fix: Pods/ mit actions/cache cachen; Key = Podfile.lock-Hash + github.ref + arm64. In CI pod install --deployment nutzen.

2.2 Swift Package Manager (SPM)

Typische Kosten: Package-Graph auflösen 1–5 Minuten.

Ursache: jedes Mal neu auflösen; .build weg; Package.resolved nicht im Cache-Key.

Fix: ~/Library/Caches/org.swift.swiftpm und .build cachen; Key enthält Package.resolved-Hash (siehe §3.2).

2.3 Xcode DerivedData

Typischer Cold-Zuschlag: voller oder fast voller Compile 5–15 Minuten.

Ursache: DerivedData nicht wiederverwendet → voller Swift-Compile, Asset-Reprocessing, Modul-Rebuild.

Fix: xcodebuild -derivedDataPath DerivedData und diesen Pfad cachen (siehe §3.3).

Team prüft GitHub-Actions-Workflow für CocoaPods-, SPM- und DerivedData-Cache sowie iOS-CI-Optimierung

3. Ein funktionierendes GitHub Actions iOS-CI-Cache-Setup

Für runs-on: macos-latest. Alle drei Blöcke in denselben Job, vor pod install / xcodebuild (actions/cache@v4 speichert automatisch).

3.1 CocoaPods-Cache (Pflicht)

CocoaPods-Cache · 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-Cache (Pflicht)

SPM-Cache · 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-Cache (hoher Impact)

DerivedData-Cache · 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 ...

Vor dem Vergleich der Schrittzeiten auf Cache hit occurred in den Logs warten. Bei Miss zuerst Key und Pfad fixen — nicht gleich die Xcode-Version beschuldigen.

4. Cache-Key-Design (nicht überspringen)

Viele iOS-CI-Optimierungen scheitern an Keys, nicht an Runnern.

✔ Muss rein ❌ Typische Fehler
Architektur (arm64) Kein arm64/x86-Split — Runner wechseln, alles miss
Branch (github.ref) Nur Lockfile — DerivedData läuft über Branches
Lockfile-Hash restore-keys zu breit (z. B. nur dd-) → falscher Hit
restore-keys-Fallback

Bei Lockfile-Änderung kann ein Präfix wie dd-arm64-${{ github.ref }}- Cache teilweise wiederverwenden. Mehrere Schemes? ${{ matrix.scheme }} in den Key. Parallele Jobs auf einem Runner dürfen keinen gemeinsamen DerivedData-Root teilen — mit ${{ github.run_id }}-Unterverzeichnissen isolieren.

5. Self-hosted / Cloud Mac (fortgeschritten)

Auf Mac mini oder Cloud Mac als Self-hosted Runner sind Sie nicht auf actions/cache beschränkt — die Platte bleibt, warm builds sind stabiler:

  • Fester DerivedData-Pfad
  • Festes Pods-Verzeichnis
  • Warm-Cache auf der Platte (spart 30–90 s Upload/Download pro Job)
Self-hosted · feste Pfade
export DERIVED_DATA=/Volumes/Data/DerivedData/App-${{ github.run_id }}
export PODS_ROOT=/Volumes/Data/Pods/${{ github.ref_name }}

Vollständiges Job-Beispiel und 1-TB-Datenplatte: Workflow unten und CI/CD-Anbindung FAQ.

Self-hosted · feste 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 ≠ langsamer Runner (häufige Fehldeutung)

Teams schieben langsames GitHub Actions iOS CI oft auf Runner oder Xcode-Version. Häufiger:

Was Sie sehen Wahrscheinlichere Ursache
Build plötzlich langsamer Cache-Miss
P95 wackelt Cold Builds in warm-Statistik gemischt
Zufällige Verlangsamungen DerivedData-Konkurrenz bei parallelen Jobs
Dependencies von vorn Falscher Cache-Key

Kombinieren mit dem Varianz-Guide: cold/warm trennen → Cache tunen → dann Hardware (2026: Warum iOS CI/CD auf dem Mac mini M4 läuft).

7. Gemessene Gewinne

Nur Cache-Fixes, typische Einsparungen:

Schicht Zusatzzeit bei Cold-Miss Nach Cache-Verdrahtung
CocoaPods 3–8 min warm oft <30 s–3 min
SPM 1–5 min resolve bei Hit deutlich kürzer
DerivedData 5–15 min warm meist inkrementeller Compile

In unserem 14-Tage-Shadow-Lauf hat nur Cache-Optimierung die warm-Wandzeit um etwa −1:40 gekürzt. Queue weg und Self-hosted mit fester Platte: warm P95 14:12 → 6:05 (−57 %) — siehe Optimierungsübersicht.

8. FAQ

Warum ist GitHub Actions iOS CI so langsam?

Meist nicht die CPU — CocoaPods / SPM / DerivedData ohne Cache oder mit falschen Keys. Ephemeral Runner verstärken jeden Miss.

Wie cache ich CocoaPods auf GitHub Actions?

Pods/ cachen; Key: pods-arm64-${{ github.ref }}-${{ hashFiles('**/Podfile.lock') }}. Siehe §3.1.

Wie cache ich SPM in iOS CI?

Globalen swiftpm-Ordner und .build cachen; Key an Package.resolved binden. Siehe §3.2.

Welchen Pfad soll der DerivedData-Cache nutzen?

actions/cache path muss zu xcodebuild -derivedDataPath passen; System-Default ist nicht nötig.

Cache zu groß?

GitHub begrenzt Einträge auf etwa 10 GB. DerivedData-Keys nach Scheme splitten oder Self-hosted mit fester Platte ohne Upload.

macos-latest vs. self-hosted?

Hosted: nur actions/cache, kann zwischen Jobs leeren. Self-hosted: festes /Volumes/Data, stabilere warm builds. Vergleich in der Optimierungsübersicht.

9. Fazit und verwandte Guides

Der höchste ROI bei iOS-CI-Optimierung ist oft CocoaPods-, SPM- und DerivedData-Cache — vor dem Chip-Tausch. Workflow heute anpassen und Test-PR laufen lassen.

Gleiche Serie:

Feste DerivedData- und Pods-Pfade gewünscht?

Vuncloud Cloud Mac M4 Pro mit 1 TB Datenplatte — für Self-hosted iOS CI: weniger actions/cache-Shuffle, stabilere warm builds.

Cloud Mac Pakete · CI/CD-Anbindung FAQ

Cloud Lab · iOS CI

iOS CI langsam? Zuerst diese drei Caches prüfen

CocoaPods · SPM · DerivedData · Workflow-Beispiele

Wasserfall −1:40
Zeitlich begrenzt Pakete ansehen