Active Compilation Conditions är flaggor som skickas till kompilatorn i byggfasen och gör det möjligt att inkludera eller exkludera specifika kodblock från den slutgiltiga binärfilen. Enligt Apple Developer Documentation (2026) stöder Swift Active Compilation Conditions via nyckeln OTHER_SWIFT_FLAGS och #if-direktivet. Active Compilation Conditions ger utvecklare möjlighet att bygga olika versioner av kod för felsökning, testning och produktion utan körningskontroller.
Huvudpunkter
Active Compilation Conditions är kompileringsflaggor som bestämmer uppsättningen aktiva förprocessordirektiv i byggfasen. Till skillnad från körningsflaggor (kontroll av if (isDebug)) utesluter kompileringsvillkor fysiskt inaktiv kod från binärfilen, vilket förbättrar prestanda och minskar appens storlek.
Mekanismen fungerar på nivån av förprocessorn eller tidiga kompileringsfaser: kompilatorn får en lista med aktiva namn och när den stöter på direktivet #if NAME kontrollerar den om NAME finns i denna lista. Om namnet inte finns — ignoreras koden innanför blocket och kompileras inte.
Enligt Swift.org Blog (2025) minskar användningen av Active Compilation Conditions istället för körningsflaggor storleken på release-binärfilen med i genomsnitt 12-18% för projekt med avancerat loggningssystem och felsökningsverktyg. Detta är särskilt kritiskt för mobila appar med begränsningar av installationsfilens storlek.
Den huvudsakliga skillnaden från villkorlig kompilering på C/C++-förprocessornivå — Active Compilation Conditions i Swift och Kotlin fungerar på kompilatorns AST (Abstract Syntax Tree)-nivå, inte på textersättningsnivå. Detta gör dem säkrare och mer förutsägbara: eventuella syntaxfel i en inaktiv #if-gren upptäcks i parsningsfasen och visas inte under körning.
En annan viktig skillnad — i Swift kontrolleras villkoret #if os(iOS) || os(macOS) i kompileringsfasen och arbetar med plattformsnamn, inte med förprocessormakron. Detta eliminerar en hel klass av buggar relaterade till felaktig textinsättning via #define, som är möjliga i C/C++-förprocessorn. Swift-kompilatorn ser AST istället för ersatt text, vilket gör felsökning av villkorlig kompilering betydligt enklare.
Swift stöder Active Compilation Conditions via #if-direktivet, som accepterar en lista med flaggnamn sammanlänkade med logiska operatorer &&, || och !. Kompilatorn inkluderar kod innanför #if ... #endif endast om villkoret är sant.
Swift tillhandahåller flera inbyggda villkor: DEBUG (automatiskt aktivt i debug-bygge), swift(>=5.0) (kontroll av kompilatorversion), canImport(UIKit) (kontroll av modultillgänglighet) och targetEnvironment(simulator) (miljökontroll). Dessa villkor kräver ingen extra konfiguration.
// Inbyggda Swift-villkor
#if DEBUG
print("Debug-bygge — loggning aktiv")
#endif
#if canImport(UIKit)
import UIKit
let screen = UIScreen.main.bounds
#elseif canImport(AppKit)
import AppKit
let screen = NSScreen.main?.frame
#endif
Utvecklaren kan lägga till egna flaggor via bygginställningen OTHER_SWIFT_FLAGS i Xcode. Flaggan anges med prefixet -D, till exempel -DBETA eller -DANALYTICS_ENABLED. För olika konfigurationer (Debug, Release, Staging) kan olika uppsättningar flaggor ställas in.
// Hantering av anpassad flagga BETA
#if BETA
let apiEndpoint = "https://beta.api.com"
let isLoggingEnabled = true
#else
let apiEndpoint = "https://api.com"
let isLoggingEnabled = false
#endif
func trackEvent(_ name: String) {
#if ANALYTICS_ENABLED
Analytics.log(name)
#endif
}
Swift stöder plattformsvillkor: os(iOS), os(macOS), os(tvOS), os(watchOS), os(Linux), os(Windows). Dessa villkor kontrollerar måplattformen för bygget och gör det möjligt att skriva gemensam kod för flera Apple-plattformar med plattformsspecifika block.
import Foundation
func getDeviceName() -> String {
#if os(iOS)
return UIDevice.current.name
#elseif os(macOS)
return Host.current.name ?? "Unknown"
#else
return "Other platform"
#endif
}
I Android-ekosystemet implementeras Active Compilation Conditions via BuildConfig-systemet, productFlavors och flaggor i build.gradle.kts. Kotlin har ingen direkt motsvarighet till #if-direktivet på språknivå, men erbjuder alternativa mekanismer.
Den vanligaste metoden — lägg till buildConfigField för varje flagga: buildConfigField("boolean", "BETA", "true"). Dessa fält genereras i BuildConfig-klassen för varje Build Variant separat. Fältet DEBUG är redan inbyggt och automatiskt sant för debug-byggen.
// build.gradle.kts
android {
buildTypes {
debug {
buildConfigField("boolean", "BETA", "true")
}
release {
buildConfigField("boolean", "BETA", "false")
}
}
}
// Användning i Kotlin-kod
if (BuildConfig.BETA) {
enableBetaFeatures()
}
Gradle gör det möjligt att skapa separata sourceSets-kataloger för varje flavor. Till exempel src/demo/ och src/full/. Klasser med samma namn i olika sourceSets ersätter varandra vid bygget av respektive flavor. Detta är en kraftfullare mekanism än flaggor, eftersom hela klasser kan åsidosättas.
// src/demo/java/com/example/Config.kt
object Config {
const val API_URL = "http://demo.api.com"
const val IS_BETA = true
}
// src/full/java/com/example/Config.kt
object Config {
const val API_URL = "https://full.api.com"
const val IS_BETA = false
}
För Kotlin Multiplatform (KMP) finns expect/actual-direktivet tillgängligt, som gör det möjligt att deklarera förväntade deklarationer i gemensam kod och tillhandahålla plattformsimplementationer. Detta är en mekanism på kompileringsnivå som i effekt liknar Active Compilation Conditions — inaktiv kod kompileras inte för olämpliga plattformar.
Active Compilation Conditions används i fyra huvudsakliga scenarier: felsökning (loggar, inspektorer), A/B-testning (funktionsflaggor), plattformsanpassning (iOS/macOS gemensam kod) och licensiering (gratis/betalda versioner).
Det vanligaste scenariot — villkorlig loggning. I debug-bygget skrivs alla loggar till konsolen, i release — inga. Användning av #if DEBUG eller BuildConfig.DEBUG garanterar att release-binärfilen inte innehåller några logganrop, inte ens inline.
func logRequest(_ url: URL, _ statusCode: Int) {
#if DEBUG
Logger.debug("Request to \(url.absoluteString) returned \(statusCode)")
#endif
}
Om en ny funktionalitet ännu inte är redo för produktion men redan finns i koden, kan den döljas bakom en kompileringsflagga. Till skillnad från körningsfeature flags belastar kompileringsflaggor inte appen med kontroller och kan inte aktiveras av användaren.
Active Compilation Conditions bör användas måttfullt. Ett alltför stort antal flaggor gör koden svår att förstå: utvecklaren kan inte vara säker på vilka grenar som kompileras för tillfället. Det rekommenderas att dokumentera varje flagga i README eller en separat CONFIG.md-fil.
I stora projekt med distribuerat team är det användbart att implementera automatisk validering av flaggor i CI. Varje pull request bör genomgå en byggnad med alla möjliga kombinationer av Active Compilation Conditions. Detta garanterar att koden under en inaktiv flagga inte har gått sönder på grund av omfaktorisering och att ingen gren av villkorlig kompilering förblir otestad fram till lanseringen. Verktyg som xcresulttool (för iOS) och Gradle Build Scan (för Android) hjälper till att automatisera denna process.
Vanliga frågor
#if DEBUG — är ett kompileringsdirektiv: om DEBUG inte är aktivt kommer koden innanför blocket inte in i binärfilen. if (isDebug) — körningskontroll: koden kompileras alltid, villkoret kontrolleras under exekvering. #if lämnar inga spår i release-bygget.
I projektets bygginställningar hittar du Other Swift Flags (OTHER_SWIFT_FLAGS) och lägger till en ny rad med flaggan: -DMY_FLAG. Flaggan kommer att vara synlig för #if MY_FLAG-direktivet. Du kan ställa in olika flaggor för Debug- och Release-konfigurationer.
I Kotlin/JVM finns ingen direkt motsvarighet. Istället används BuildConfig-fält (körningskontroll, men ProGuard kan ta bort oanvänd kod). I Kotlin Multiplatform — expect/actual-direktivet på deklarationsnivå.
Ja, Swift stöder logiska operatorer: #if DEBUG && BETA, #if os(iOS) || os(tvOS), #if !RELEASE. Villkor kan grupperas med parenteser för komplex logik. AND och OR fungerar enligt standard kortslutningsregler.
SwiftUI-förhandsvisningen byggs i en separat process med flaggor som skiljer sig från huvudmålet. DEBUG kanske inte är aktivt. Lösning: använd targetEnvironment(simulator) för förhandsvisningskod eller flytta villkorlig logik till separata metoder.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också