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 wiederholtpod install - Swift Package Manager (SPM): Abhängigkeitsgraph neu aufgelöst;
.buildpro 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).
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:
- Abhängigkeiten neu auflösen (CocoaPods / SPM)
- DerivedData Cold Starts (Voll-Recompile)
- 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).
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)
- 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)
- 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)
- 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 |
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)
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.
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:
- iOS CI langsam? Warum xcodebuild auf GitHub Actions schwankt — cold/warm, P95-Statistik
- GitHub Actions macOS Runner-Optimierung: P95 57 % schneller + iOS-CI-Playbook — P95 −57 %, Shadow-Wasserfall
- Kaufen vs. mieten · 500 iOS-Builds pro Monat – Mac mini kaufen oder Mac Cloud Server mieten?
- 2026: Warum iOS CI/CD auf dem Mac mini M4 läuft · CI/CD-Anbindung FAQ
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.