Scheme in Xcode is een configuratie die bepaalt hoe de app voor iOS, macOS, watchOS of tvOS wordt gebouwd, getest, geprofileerd en gearchiveerd. Elke Scheme bevat een set acties (Build, Run, Test, Profile, Analyze, Archive) met eigen parameters, argumenten en omgevingsvariabelen. Volgens Apple Developer Documentation, 2025 is Scheme het belangrijkste hulpmiddel voor het beheren van buildconfiguraties in Xcode, ter vervanging van handmatig omschakelen van parameters. Xcode maakt automatisch een schema aan voor elk target bij de eerste keer openen van het project.
Belangrijkste punten
Scheme in Xcode is een XML-bestand (extensie .xcscheme) dat de reeks acties en hun parameters beschrijft voor het bouwen en analyseren van de app. Elke Scheme is gekoppeld aan een of meer targets en bepaalt met welke configuratie (Debug, Release, AdHoc) elke actie wordt uitgevoerd. Scheme is een tegenhanger van Build Variant in Android, maar met een flexibelere structuur: één schema kan verschillende targets bevatten voor verschillende acties.
Xcode maakt automatisch een schema aan voor elk target bij de eerste keer openen van het project. De standaardnaam van het schema komt overeen met de naam van het target. Als het project een testtarget bevat, voegt Xcode dit automatisch toe aan de Test-actie van het schema van het hoofdtarget. Voor projecten met meerdere targets (hoofdapp + watchOS + extension) maakt Xcode een apart schema voor elk, maar je kunt ook één schema maken dat alle targets tegelijk bouwt.
Schema's worden opgeslagen in de map xcshareddata/xcschemes/ (voor shared) of xcuserdata/<user>/xcschemes/ (voor private). Shared-schema's komen in Git terecht en worden door het hele team gebruikt. Private-schema's worden lokaal opgeslagen en niet gesynchroniseerd. Het .xcscheme-bestand heeft een XML-indeling met het root-element <Scheme>. Binnenin staan blokken voor elke actie: BuildAction, TestAction, LaunchAction, ProfileAction, AnalyzeAction, ArchiveAction.
.xcscheme is een XML-bestand dat handmatig of via Xcode kan worden bewerkt. Belangrijkste elementen: <BuildAction> (lijst van te bouwen targets), <TestAction> (verwijzingen naar testtargets), <LaunchAction> (uitvoeringsconfiguratie), <ProfileAction>, <AnalyzeAction>, <ArchiveAction>. Elk blok bevat het attribuut buildConfiguration, dat bepaalt welke configuratie (Debug/Release) voor deze actie moet worden gebruikt.
Scheme bestaat uit zes acties, die elk onafhankelijk kunnen worden geconfigureerd. Build Action bepaalt welke targets worden gebouwd en in welke volgorde. Run Action — hoe de app wordt uitgevoerd: met welke argumenten, omgevingsvariabelen en configuratie. Test Action — welke tests worden uitgevoerd en welke code coverage-opties zijn ingeschakeld. Profile Action — uitvoeren met Instruments-tools voor profilering. Analyze Action — statische code-analyse met Clang Static Analyzer. Archive Action — bouwen voor publicatie in de App Store of AdHoc-distributie.
Voor elke actie kan een aparte build configuration worden ingesteld. Meestal wordt voor Run en Test Debug gebruikt en voor Archive Release. De build configuration bepaalt de set compilerflags, optimalisaties en debug-informatie. Xcode biedt twee standaardconfiguraties: Debug (zonder optimalisaties, met debugsymbolen) en Release (met optimalisaties, zonder debug-informatie). De ontwikkelaar kan aangepaste configuraties toevoegen via project.xcconfig.
De actie Archive is bijzonder belangrijk — deze maakt een .xcarchive aan, dat vervolgens wordt geëxporteerd naar .ipa voor de App Store of AdHoc. Archive Action gebruikt standaard de Release-configuratie, maar je kunt overschakelen naar AdHoc of Distribution. In Archive Action is ook de vlag revealArchiveInOrganizer beschikbaar — na voltooiing van het archiveren opent Xcode de Organiser voor verdere acties met het archief.
<!-- Voorbeeld van een .xcscheme voor een iOS-app -->
<Scheme
LastUpgradeVersion = "1500"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ABCD1234"
BuildableName = "MyApp.app"
BlueprintName = "MyApp"
ReferencedContainer = "container:MyApp.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
enableAddressSanitizer = "YES">
</LaunchAction>
</Scheme>
Het aanmaken van een nieuw schema gebeurt via het Xcode-menu: Product → Scheme → New Scheme of met de knop „+“ in het Scheme-paneel (naast de Run-knop). Bij het aanmaken wordt het target geselecteerd waarvoor het schema wordt gemaakt. Als het schema als „duplicate“ is geselecteerd, kopieert Xcode automatisch de instellingen van het bestaande schema. Nieuwe schema's worden standaard als private opgeslagen — om ze met het team te delen, moet Shared worden ingeschakeld in Manage Schemes.
Het venster Edit Scheme (Product → Scheme → Edit Scheme) bevat zes tabbladen, één voor elke actie. Op elk tabblad kunnen de build configuration, startargumenten, omgevingsvariabelen en diagnostische vlaggen worden gewijzigd. Op het tabblad Run zijn de volgende opties beschikbaar: executable (welke binary moet worden uitgevoerd), wait for executable to be launched (voor het debuggen van gestarte processen), debugger (LLDB of None), launch arguments, environment variables en geavanceerde opties (Address Sanitizer, Thread Sanitizer, Main Thread Checker, Memory Management).
Voor diagnostiek: Address Sanitizer (ASan) — detecteert uitbreiding buiten de grenzen van arrays, use-after-free en andere geheugenfouten in C/C++/ObjC-code. Thread Sanitizer (TSan) — detecteert race-omstandigheden (data races) in multithreaded code. Undefined Behavior Sanitizer (UBSan) — legt ongedefinieerd gedrag bloot, bijvoorbeeld overflow van een signed int. Deze opties zijn beschikbaar in Edit Scheme → Run → Diagnostics en werken alleen voor Debug-builds. Het inschakelen van alle sanitizers kan het opstarten 2-3 keer vertragen, daarom wordt aangeraden ze selectief in te schakelen.
Typische praktijk — aparte schema's maken voor elke omgeving: Dev, Staging, Production. Elk schema gebruikt dezelfde Build Configuration (Debug voor Dev, Release voor Production), maar verschillende startargumenten: -FIRAnalyticsDebugEnabled, -com.apple.CoreData.SQLDebug 1 voor Dev en hun afwezigheid voor Production. Startargumenten worden doorgegeven aan UserDefaults (ProcessInfo.processInfo.arguments) en zijn beschikbaar om te lezen bij het opstarten van de app. Hierdoor kunnen server-URL, logniveau en functies worden gewijzigd zonder code-aanpassing.
Shared-schema's worden opgeslagen in <project>.xcworkspace/xcshareddata/xcschemes/ of <project>.xcodeproj/xcshareddata/xcschemes/ en komen in de Git-repository terecht. Alle ontwikkelaars van het team zien deze schema's in Xcode. Shared-schema's zijn de enige manier om schema's binnen het team te verspreiden. Als een ontwikkelaar een belangrijk schema heeft gemaakt (bijvoorbeeld „Staging Archive“), maar dit niet als Shared heeft gemarkeerd, zal de rest van het team het niet zien, wat tot verwarring leidt: iedereen maakt zijn eigen schema met eigen instellingen.
Private-schema's worden opgeslagen in xcuserdata/<user>/xcschemes/ en komen niet in Git terecht. Ze zijn handig voor persoonlijke configuraties: bijvoorbeeld een schema met alle sanitizers ingeschakeld voor een specifieke ontwikkelaar. Private-schema's mogen geen kritieke instellingen bevatten waarvan de build van het project afhankelijk is — als de ontwikkelaar het project verlaat, verdwijnen zijn private-schema's. Aanbeveling: maak alle schema's die in CI/CD worden gebruikt en door minstens twee ontwikkelaars Shared.
Schema's worden beheerd via Manage Schemes (Product → Scheme → Manage Schemes). In het venster worden alle schema's van het project weergegeven, hun status (Shared/Private) en de knoppen +/— voor toevoegen/verwijderen. Het selectievakje Shared schakelt de zichtbaarheid van het schema voor het team om. Bij een Git-conflict (wijzigingen in .xcscheme door twee ontwikkelaars) moet de merge zorgvuldig worden opgelost — XML-bestanden kunnen verschillende target-identificatoren bevatten. Het wordt aanbevolen om .xcscheme toe te voegen aan bestanden die bij merge worden vergrendeld (git lfs of .gitattributes).
Arguments in Scheme zijn de strings die bij het uitvoeren aan de app worden doorgegeven (ProcessInfo.processInfo.arguments) en omgevingsvariabelen (ProcessInfo.processInfo.environment). Argumenten worden gebruikt voor vlaggen: -AppleLanguages (ru), -AppleLocale ru_RU voor het simuleren van de Russische locale of -FIRDebugEnabled voor het inschakelen van Firebase-debugging. Omgevingsvariabelen worden toegepast voor configuratie: API_BASE_URL=http://localhost:3000, LOG_LEVEL=debug.
Voor het beheren van features (feature flags) in verschillende omgevingen wordt de combinatie Arguments + Build Configuration gebruikt. In het Dev-schema wordt het argument -FeatureFlagNewOnboarding YES ingesteld en in Production — -FeatureFlagNewOnboarding NO (of het argument ontbreekt). In de code de controle: UserDefaults.standard.bool(forKey: "FeatureFlagNewOnboarding"). Deze aanpak maakt het mogelijk om features stapsgewijs in staging in te schakelen zonder code te wijzigen en zonder productiewaarden te committen.
Belangrijk: argumenten en omgevingsvariabelen van Scheme overschrijven de waarden uit Info.plist. Als in Info.plist API_URL is opgegeven en in Scheme — API_URL=http://localhost voor Run Action, dan wordt bij uitvoeren vanuit Xcode de waarde uit Scheme gebruikt. Bij uitvoeren vanaf het apparaat (niet vanuit Xcode) — de waarde uit Info.plist. Dit is handig voor lokale ontwikkeling, maar bedenk dat Scheme-variabelen niet in de build terechtkomen — ze werken alleen bij uitvoeren via Xcode.
import Foundation
struct AppEnvironment {
var apiBaseURL: String {
ProcessInfo.processInfo.environment["API_BASE_URL"]
?? Bundle.main.object(forInfoDictionaryKey: "API_BASE_URL") as? String
?? "https://api.production.com"
}
var isDebugMode: Bool {
ProcessInfo.processInfo.arguments.contains("-DebugModeEnabled")
}
var isNewOnboardingEnabled: Bool {
UserDefaults.standard.bool(forKey: "FeatureFlagNewOnboarding")
}
}
// Wordt gebruikt bij het opstarten
let env = AppEnvironment()
NetworkConfig.shared.configure(baseURL: env.apiBaseURL)
In CI/CD (GitHub Actions, Jenkins, GitLab CI) wordt Scheme gebruikt als het belangrijkste argument van het commando xcodebuild. Voorbeeld: xcodebuild -workspace MyApp.xcworkspace -scheme MyApp -configuration Release -sdk iphoneos archive. De vlag -scheme geeft aan welk schema moet worden gebruikt. xcodebuild leest alle instellingen uit het .xcscheme-bestand, inclusief build configuration, targets en buildvolgorde. Dit garandeert dat CI/CD de app met dezelfde parameters bouwt als de lokale IDE.
Voor CI/CD zijn Shared-schema's van cruciaal belang. Als een schema niet Shared is, vindt xcodebuild het niet in de repository en mislukt de build met de fout „Scheme not found“. Regel: controleer vóór het configureren van CI/CD dat alle gebruikte schema's als Shared zijn gemarkeerd. Tweede regel: gebruik in CI/CD niet het standaardschema (Xcode selecteert automatisch het eerste schema) — geef altijd expliciet de naam van het schema door via de vlag -scheme.
Voor parallelle builds van meerdere schema's (bijvoorbeeld de app en de watchOS-extension) kan xcodebuild opeenvolgend of parallel worden uitgevoerd. Moderne CI-systemen maken het mogelijk om de build van verschillende schema's te parallelliseren via een matrix: de ene job bouwt de iOS-app, de tweede — de watchOS-extension. Dit verkort de totale buildtijd van 15 naar 8 minuten met twee parallelle agents. Aan het einde worden de artefacten gecombineerd tot één .xcarchive met xcodebuild -exportArchive.
#!/bin/bash — CI/CD-build met xcodebuild
# 1. Opschonen en bouwen
xcodebuild clean archive \
-workspace "MyApp.xcworkspace" \
-scheme "MyApp Production" \
-configuration Release \
-sdk iphoneos \
-archivePath "build/MyApp.xcarchive" \
CODE_SIGN_STYLE="Manual" \
PROVISIONING_PROFILE_SPECIFIER="match AppStore"
# 2. Exporteren naar IPA
xcodebuild -exportArchive \
-archivePath "build/MyApp.xcarchive" \
-exportPath "build/ipa" \
-exportOptionsPlist "ExportOptions.plist"
Veelgestelde vragen
Meestal volstaan 2-3 schema's: Development (Debug), Staging (met argumenten voor de testserver) en Production (Release). Voor modulaire bibliotheken — één schema met instellingen voor testen. Vermenigvuldig schema's niet — elk nieuw schema vereist onderhoud.
Build Configuration (Debug/Release) — een set compilerflags die is gedefinieerd in .xcconfig. Scheme — een set acties, elk verwijst naar een Build Configuration. Het schema zegt „gebruik bij uitvoeren Debug“, de configuratie definieert „Debug betekent zonder optimalisaties, met symbolen“.
Argumenten komen terecht in ProcessInfo.processInfo.arguments en UserDefaults (als het argument met een streepje begint). Omgevingsvariabelen — in ProcessInfo.processInfo.environment. In de code: UserDefaults.standard.bool(forKey: "FeatureFlag") voor argumenten van de vorm -FeatureFlag YES.
Ja, in Build Action kunnen meerdere targets worden toegevoegd. Zo bouwt het schema „App + Watch + Widget“ alle drie de targets opeenvolgend (als parallelizeBuildables=NO) of parallel (YES). Voor het archiveren van de app volstaat het hoofdtarget — de andere worden als dependencies gebouwd.
Swift Package Manager vervangt schema's niet — het schema bepaalt nog steeds met welke configuratie de SPM-dependencies worden gebouwd, welke tests worden uitgevoerd en hoe wordt gearchiveerd. SPM-pakketten kunnen eigen schema's hebben die automatisch in het project worden geïmporteerd bij het toevoegen van het pakket.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook