Active Compilation Conditions sunt flaguri transmise compilatorului în faza de build care permit includerea sau excluderea anumitor blocuri de cod din fișierul binar final. Conform Apple Developer Documentation (2026), Swift suportă Active Compilation Conditions prin cheia OTHER_SWIFT_FLAGS și directiva #if. Active Compilation Conditions oferă dezvoltatorilor posibilitatea de a construi diferite versiuni de cod pentru debug, testare și producție fără verificări în runtime.
Principalele puncte
Active Compilation Conditions sunt flaguri de compilare care determină setul de directive active ale preprocesorului în faza de build. Spre deosebire de flagurile runtime (verificarea if (isDebug)), condițiile de compilare exclud fizic codul inactiv din fișierul binar, ceea ce îmbunătățește performanța și reduce dimensiunea aplicației.
Mecanismul funcționează la nivelul preprocesorului sau fazelor incipiente de compilare: compilatorul primește o listă de nume active și când întâlnește directiva #if NAME verifică dacă NAME se află în această listă. Dacă numele nu există — codul din interiorul blocului este ignorat și nu se compilează.
Conform Swift.org Blog (2025), utilizarea Active Compilation Conditions în locul flagurilor runtime reduce dimensiunea binarului release în medie cu 12-18% pentru proiectele cu un sistem avansat de logare și instrumente de debug. Acest lucru este deosebit de critic pentru aplicațiile mobile cu limitări ale dimensiunii fișierului de instalare.
Diferența principală față de compilarea condiționată la nivelul preprocesorului C/C++ — Active Compilation Conditions în Swift și Kotlin funcționează la nivelul AST (Abstract Syntax Tree) al compilatorului, nu la nivelul înlocuirii de text. Acest lucru le face mai sigure și mai predictibile: orice eroare sintactică în ramura inactivă #if va fi detectată în faza de parsare, nu va apărea în runtime.
O altă diferență importantă — în Swift condiția #if os(iOS) || os(macOS) este verificată în faza de compilare și funcționează cu nume de platforme, nu cu macro-uri de preprocesor. Aceasta elimină o întreagă clasă de buguri legate de inserarea incorectă a textului prin #define, posibile în preprocesorul C/C++. Compilatorul Swift vede AST, nu textul înlocuit, ceea ce face debugging-ul compilării condiționate mult mai ușor.
Swift suportă Active Compilation Conditions prin directiva #if, care acceptă o listă de nume de flaguri unite prin operatori logici &&, || și !. Compilatorul include codul din #if ... #endif doar dacă condiția este adevărată.
Swift oferă mai multe condiții încorporate: DEBUG (activat automat în build-ul de debug), swift(>=5.0) (verificarea versiunii compilatorului), canImport(UIKit) (verificarea disponibilității modulului) și targetEnvironment(simulator) (verificarea mediului). Aceste condiții nu necesită configurare suplimentară.
// Condiții încorporate Swift
#if DEBUG
print("Build de debug — logare activă")
#endif
#if canImport(UIKit)
import UIKit
let screen = UIScreen.main.bounds
#elseif canImport(AppKit)
import AppKit
let screen = NSScreen.main?.frame
#endif
Dezvoltatorul poate adăuga propriile flaguri prin Build Setting OTHER_SWIFT_FLAGS în Xcode. Flagul se specifică cu prefixul -D, de exemplu -DBETA sau -DANALYTICS_ENABLED. Pentru diferite configurații (Debug, Release, Staging) se pot seta seturi diferite de flaguri.
// Gestionarea flagului personalizat 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 suportă condiții de platformă: os(iOS), os(macOS), os(tvOS), os(watchOS), os(Linux), os(Windows). Aceste condiții verifică platforma țintă de build și permit scrierea de cod comun pentru mai multe platforme Apple cu blocuri specifice platformei.
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
}
În ecosistemul Android, Active Compilation Conditions sunt implementate prin sistemul BuildConfig, productFlavors și flaguri în build.gradle.kts. Kotlin nu are un analog direct al directivei #if la nivelul limbajului, dar oferă mecanisme alternative.
Cea mai comună metodă — adăugarea buildConfigField pentru fiecare flag: buildConfigField("boolean", "BETA", "true"). Aceste câmpuri sunt generate în clasa BuildConfig pentru fiecare Build Variant separat. Câmpul DEBUG este deja încorporat și automat true pentru build-urile de debug.
// build.gradle.kts
android {
buildTypes {
debug {
buildConfigField("boolean", "BETA", "true")
}
release {
buildConfigField("boolean", "BETA", "false")
}
}
}
// Utilizare în codul Kotlin
if (BuildConfig.BETA) {
enableBetaFeatures()
}
Gradle permite crearea de directoare sourceSets separate pentru fiecare flavor. De exemplu, src/demo/ și src/full/. Clasele cu același nume în sourceSets diferite se înlocuiesc reciproc la build-ul flavorului respectiv. Acesta este un mecanism mai puternic decât flagurile, deoarece se pot suprascrie clase întregi.
// 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
}
Pentru Kotlin Multiplatform (KMP) este disponibilă directiva expect/actual, care permite declararea declarațiilor așteptate în codul comun și furnizarea implementărilor de platformă. Este un mecanism la nivel de compilare, similar ca efect cu Active Compilation Conditions — codul inactiv nu se compilează pentru platformele nepotrivite.
Active Compilation Conditions sunt utilizate în patru scenarii principale: debugging (loguri, inspectori), testare A/B (flaguri de funcții), adaptare la platformă (cod comun iOS/macOS) și licențiere (versiuni gratuite/plătite).
Cel mai frecvent scenariu — logare condiționată. În build-ul de debug toate logurile sunt scrise în consolă, în release — niciunul. Utilizarea #if DEBUG sau BuildConfig.DEBUG garantează că binarul release nu conține nicio apelare de logger, nici măcar inline.
func logRequest(_ url: URL, _ statusCode: Int) {
#if DEBUG
Logger.debug("Request to \(url.absoluteString) returned \(statusCode)")
#endif
}
Dacă o funcționalitate nouă nu este încă gata pentru producție, dar există deja în cod, poate fi ascunsă în spatele unui flag de compilare. Spre deosebire de runtime feature flags, flagurile de compilare nu încarcă aplicația cu verificări și nu pot fi activate de utilizator.
Active Compilation Conditions trebuie utilizate cu moderație. Un număr excesiv de flaguri face codul greu de înțeles: dezvoltatorul nu poate fi sigur ce ramuri se compilează în acest moment. Se recomandă documentarea fiecărui flag în README sau într-un fișier special CONFIG.md.
În proiectele mari cu o echipă distribuită, este utilă implementarea validării automate a flagurilor în CI. Fiecare pull request trebuie să treacă prin build cu toate combinațiile posibile de Active Compilation Conditions. Aceasta garantează că codul sub un flag inactiv nu s-a stricat din cauza refactorizării și nicio ramură de compilare condiționată nu a rămas neverificată până la lansare. Instrumente precum xcresulttool (pentru iOS) și Gradle Build Scan (pentru Android) ajută la automatizarea acestui proces.
Întrebări frecvente
#if DEBUG — este o directivă de compilare: dacă DEBUG nu este activ, codul din interiorul blocului nu ajunge în binar. if (isDebug) — verificare în runtime: codul se compilează întotdeauna, condiția se verifică în timpul execuției. #if nu lasă urme în build-ul release.
În Build Settings ale proiectului găsiți Other Swift Flags (OTHER_SWIFT_FLAGS) și adăugați o nouă linie cu flagul: -DMY_FLAG. Flagul va fi vizibil directivei #if MY_FLAG. Puteți seta flaguri diferite pentru configurațiile Debug și Release.
În Kotlin/JVM nu există un analog direct. În schimb se folosesc câmpurile BuildConfig (verificare în runtime, dar ProGuard poate elimina codul neutilizat). În Kotlin Multiplatform — directiva expect/actual la nivelul declarațiilor.
Da, Swift suportă operatori logici: #if DEBUG && BETA, #if os(iOS) || os(tvOS), #if !RELEASE. Condițiile pot fi grupate cu paranteze pentru logică complexă. AND și OR funcționează după regulile standard de scurtcircuitare.
Previzualizarea SwiftUI se compilează într-un proces separat cu flaguri diferite de targetul principal. DEBUG poate să nu fie activ. Soluție: utilizați targetEnvironment(simulator) pentru codul de previzualizare sau mutați logica condiționată în metode separate.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și