Active Compilation Conditions са флагове, които се предават на компилатора на етапа на изграждане и позволяват включването или изключването на определени блокове код от крайния двоичен файл. Според Apple Developer Documentation (2026), Swift поддържа Active Compilation Conditions чрез ключа OTHER_SWIFT_FLAGS и директивата #if. Active Compilation Conditions дават на разработчиците възможност да създават различни версии на код за отстраняване на грешки, тестване и продукция без проверки по време на изпълнение.
Основни моменти
Active Compilation Conditions са флагове за компилиране, които определят набора от активни директиви на препроцесора на етапа на изграждане. За разлика от флаговете по време на изпълнение (проверка if (isDebug)), условията за компилиране физически изключват неактивния код от двоичния файл, което подобрява производителността и намалява размера на приложението.
Механизмът работи на ниво препроцесор или ранни фази на компилиране: компилаторът получава списък с активни имена и когато срещне директива #if NAME, проверява дали NAME е в този списък. Ако името не съществува — кодът вътре в блока се игнорира и не се компилира.
Според Swift.org Blog (2025), използването на Active Compilation Conditions вместо флагове по време на изпълнение намалява размера на release двоичния файл средно с 12-18% за проекти с развита система за логиране и инструменти за отстраняване на грешки. Това е особено критично за мобилни приложения с ограничения на размера на инсталационния файл.
Основната разлика от условното компилиране на ниво препроцесор C/C++ — Active Compilation Conditions в Swift и Kotlin работят на ниво AST (Abstract Syntax Tree) на компилатора, а не на ниво текстова замяна. Това ги прави по-безопасни и предвидими: всяка синтактична грешка в неактивен клон #if ще бъде открита на етапа на синтактичен анализ, а няма да се прояви по време на изпълнение.
Друга важна разлика — в Swift условието #if os(iOS) || os(macOS) се проверява на етапа на компилиране и работи с имена на платформи, а не с макроси на препроцесора. Това елиминира цял клас грешки, свързани с неправилно вмъкване на текст чрез #define, които са възможни в препроцесора C/C++. Компилаторът Swift вижда AST, а не заменен текст, което прави отстраняването на грешки при условно компилиране значително по-лесно.
Swift поддържа Active Compilation Conditions чрез директива #if, която приема списък от имена на флагове, свързани с логически оператори &&, || и !. Компилаторът включва код вътре в #if ... #endif само ако условието е вярно.
Swift предоставя няколко вградени условия: DEBUG (автоматично активно в debug компилация), swift(>=5.0) (проверка на версията на компилатора), canImport(UIKit) (проверка на наличността на модул) и targetEnvironment(simulator) (проверка на средата). Тези условия не изискват допълнителна конфигурация.
// Вградени условия Swift
#if DEBUG
print("Debug компилация — логирането е активно")
#endif
#if canImport(UIKit)
import UIKit
let screen = UIScreen.main.bounds
#elseif canImport(AppKit)
import AppKit
let screen = NSScreen.main?.frame
#endif
Разработчикът може да добавя свои флагове чрез Build Setting OTHER_SWIFT_FLAGS в Xcode. Флагът се посочва с префикс -D, например -DBETA или -DANALYTICS_ENABLED. За различни конфигурации (Debug, Release, Staging) могат да се зададат различни набори от флагове.
// Обработка на собствен флаг 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 поддържа платформени условия: os(iOS), os(macOS), os(tvOS), os(watchOS), os(Linux), os(Windows). Тези условия проверяват целевата платформа за компилиране и позволяват писане на общ код за няколко платформи на Apple с платформено-специфични блокове.
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
}
В екосистемата на Android Active Compilation Conditions са имплементирани чрез системата BuildConfig, productFlavors и флагове в build.gradle.kts. Kotlin няма пряк аналог на директива #if на езиково ниво, но предоставя алтернативни механизми.
Най-честият начин — добавяне на buildConfigField за всеки флаг: buildConfigField("boolean", "BETA", "true"). Тези полета се генерират в класа BuildConfig за всеки Build Variant поотделно. Полето DEBUG е вече вградено и автоматично true за debug компилации.
// build.gradle.kts
android {
buildTypes {
debug {
buildConfigField("boolean", "BETA", "true")
}
release {
buildConfigField("boolean", "BETA", "false")
}
}
}
// Използване в код на Kotlin
if (BuildConfig.BETA) {
enableBetaFeatures()
}
Gradle позволява създаване на отделни директории sourceSets за всеки flavor. Например src/demo/ и src/full/. Класове с еднакво име в различни sourceSets се заместват взаимно при компилиране на съответния flavor. Това е по-мощен механизъм от флаговете, защото могат да бъдат презаписани цели класове.
// 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
}
За Kotlin Multiplatform (KMP) е налична директива expect/actual, която позволява деклариране на очаквани декларации в общия код и предоставяне на платформени имплементации. Това е механизъм на ниво компилиране, аналогичен по ефект на Active Compilation Conditions — неактивният код не се компилира за неподходящи платформи.
Active Compilation Conditions се използват в четири основни сценария: отстраняване на грешки (логове, инспектори), A/B тестване (флагове на функции), платформена адаптация (общ код iOS/macOS) и лицензиране (безплатни/платени версии).
Най-честият сценарий — условно логиране. В debug компилация всички логове се записват в конзолата, в release — нищо. Използването на #if DEBUG или BuildConfig.DEBUG гарантира, че release двоичният файл не съдържа никакви извиквания на логер, дори инлайн.
func logRequest(_ url: URL, _ statusCode: Int) {
#if DEBUG
Logger.debug("Request to \(url.absoluteString) returned \(statusCode)")
#endif
}
Ако нова функционалност все още не е готова за продукция, но вече съществува в кода, може да бъде скрита зад флаг за компилиране. За разлика от runtime feature flags, флаговете за компилиране не натоварват приложението с проверки и не могат да бъдат активирани от потребителя.
Active Compilation Conditions трябва да се използват умерено. Прекалено многото флагове правят кода труден за разбиране: разработчикът не може да бъде сигурен кои клонове ще се компилират в даден момент. Препоръчва се документиране на всеки флаг в README или специален файл CONFIG.md.
В големи проекти с разпределен екип е полезно да се внедри автоматична валидация на флагове в CI. Всеки pull request трябва да премине през компилация с всички възможни комбинации на Active Compilation Conditions. Това гарантира, че кодът под неактивен флаг не се е счупил поради рефакториране и нито един клон на условно компилиране не е останал непроверен до момента на издаване. Инструменти като xcresulttool (за iOS) и Gradle Build Scan (за Android) помагат за автоматизиране на този процес.
Често задавани въпроси
#if DEBUG — е директива за компилиране: ако DEBUG не е активен, кодът вътре в блока не попада в двоичния файл. if (isDebug) — проверка по време на изпълнение: кодът винаги се компилира, условието се проверява по време на изпълнение. #if не оставя следи в release компилацията.
В Build Settings на проекта намерете Other Swift Flags (OTHER_SWIFT_FLAGS) и добавете нов ред с флага: -DMY_FLAG. Флагът ще бъде видим за директива #if MY_FLAG. Можете да зададете различни флагове за Debug и Release конфигурации.
В Kotlin/JVM няма пряк аналог. Вместо това се използват полета на BuildConfig (проверка по време на изпълнение, но ProGuard може да премахне неизползвания код). В Kotlin Multiplatform — директива expect/actual на ниво декларации.
Да, Swift поддържа логически оператори: #if DEBUG && BETA, #if os(iOS) || os(tvOS), #if !RELEASE. Условията могат да се групират със скоби за сложна логика. AND и OR работят по стандартните правила за късо съединение.
SwiftUI прегледът се компилира в отделен процес с флагове, различни от основния target. DEBUG може да не е активен. Решение: използвайте targetEnvironment(simulator) за код на прегледа или изнесете условната логика в отделни методи.
Резюме
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също