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("نسخه اشکالزدایی — لاگگیری فعال است")
#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 از قبل داخلی است و برای نسخههای debug به طور خودکار true است.
// 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 هیچ فراخوانی لاگر، حتی inline شده، نداشته باشد.
func logRequest(_ url: URL, _ statusCode: Int) {
#if DEBUG
Logger.debug("Request to \(url.absoluteString) returned \(statusCode)")
#endif
}
اگر قابلیت جدید هنوز برای تولید آماده نیست اما در کد وجود دارد، میتوان آن را پشت یک پرچم کامپایل مخفی کرد. برخلاف پرچمهای ویژگی زمان اجرا، پرچمهای کامپایل برنامه را با بررسیها سنگین نمیکنند و توسط کاربر قابل فعالسازی نیستند.
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 از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید