کامپایل شرطی به کامپایلر اجازه میدهد تا بخشهایی از کد منبع را بسته به شرایطی که در مرحله ساخت مشخص هستند، شامل یا رد کند. بر اساس The Swift Programming Language (2026)، دستورالعمل #if در مرحله تحلیل AST قبل از تولید کد ماشین پردازش میشود. کامپایل شرطی به توسعهدهندگان امکان میدهد بدون تکرار، یک پایگاه کد واحد برای چندین پلتفرم و پیکربندی حفظ کنند.
نکات اصلی
کامپایل شرطی — مکانیزمی است که در آن کامپایلر دستورالعملهای کامپایل شرطی را تحلیل کرده و تنها آن بلوکهای کدی را که شرایط برای آنها برآورده میشود، در فایل باینری خروجی قرار میدهد. این امکان داشتن یک پایگاه کد واحد را فراهم میکند که با پلتفرمها و پیکربندیهای مختلف هدف سازگار میشود.
این مفهوم از C/C++ با دستورالعملهای پیشپردازنده #ifdef، #ifndef، #endif آمده است. در زبانهای مدرن (Swift، Rust، Go) این مکانیزم در سطح کامپایلر بدون پیشپردازنده جداگانه کار میکند که امنیت را افزایش میدهد: بلوکهای شرطی باید از نظر نحوی صحیح باشند، حتی اگر کامپایل نشوند.
بر اساس دادههای جلسه Apple WWDC «Embrace Swift» (2025)، حدود 40% از پروژههای Swift از کامپایل شرطی برای پشتیبانی از iOS و macOS در یک تارگت استفاده میکنند. برای پروژههای UIKit و SwiftUI، کد UI اغلب با دستورالعملهای #if os(iOS) و #if os(macOS) جدا میشود که امکان استفاده مجدد از منطق تجاری را فراهم میکند.
مزیت اصلی — ایمنی در زمان کامپایل. کد پلتفرم نامناسب نه تنها اجرا نمیشود، بلکه کامپایل هم نمیشود. این بدان معناست که خطاهای کد مخصوص iOS در هنگام ساخت برای macOS ظاهر نمیشوند و بالعکس. بررسیهای زمان اجرا چنین تضمینی را نمیدهند.
Swift چهار دستورالعمل کلیدی ارائه میدهد: #if، #elseif، #else، #endif. برخلاف پیشپردازنده C، Swift صحت نحوی کد را در همه شاخهها الزامی میکند — کامپایلر همه کد را تجزیه میکند، اما کد ماشین را فقط برای شاخههای فعال تولید میکند.
Swift از توابع بررسی داخلی پشتیبانی میکند: os(iOS)، os(macOS)، os(tvOS)، os(watchOS)، os(Linux)، os(Windows). این توابع پلتفرم هدفی را که برنامه برای آن ساخته میشود بررسی میکنند. ترکیب با && و || امکان ایجاد شرایط پیچیده را فراهم میکند.
// کد یکپارچه برای iOS، macOS و tvOS
import Foundation
class PlatformService {
func getSystemVersion() -> String {
#if os(iOS) || os(tvOS)
return UIDevice.current.systemVersion
#elseif os(macOS)
let vers = ProcessInfo.processInfo.operatingSystemVersion
return "\(vers.majorVersion).\(vers.minorVersion)"
#else
return "unknown"
#endif
}
}
Swift از بررسی نسخه کامپایلر پشتیبانی میکند: #if swift(>=5.9). این برای کتابخانهها و فریمورکهایی که از چندین نسخه Swift پشتیبانی میکنند مفید است. قابلیتهای جدید زبان (مثلاً ماکروها در Swift 5.9) میتوانند با چنین بررسی محافظت شوند.
// سازگاری با نسخههای قبلی
#if swift(>=5.9)
@MainActor
struct ModernView: View {
var body: some View {
Text("SwiftUI مدرن")
}
}
#else
struct ModernView: View {
var body: some View {
Text("SwiftUI قدیمی")
}
}
#endif
تابع canImport(ModuleName) بررسی میکند که آیا ماژول مشخص شده در محیط ساخت فعلی در دسترس است یا خیر. این انعطافپذیرترین مکانیزم است: به پلتفرم خاصی وابسته نیست. به عنوان مثال، کدی که از CoreHaptics استفاده میکند فقط در دستگاههایی که این فریمورک در دسترس است کامپایل میشود.
#if canImport(CoreHaptics)
import CoreHaptics
class HapticManager {
private var engine: CHHapticEngine?
func playTapFeedback() {
guard let engine else { return }
// پیادهسازی بازخورد لمسی
}
}
#endif
Kotlin به عنوان یک زبان دستورالعملهای پیشپردازنده ندارد. در عوض، اکوسیستم Android سه جایگزین ارائه میدهد: فیلدهای BuildConfig (بررسیهای زمان اجرا)، sourceSets (جایگزینی کل فایلها) و expect/actual (در Kotlin Multiplatform).
Gradle sourceSets امکان داشتن پیادهسازیهای مختلف کلاسها را برای طعمها یا انواع ساخت مختلف فراهم میکند. در دایرکتوری src/debug/ پیادهسازی برای debug قرار دارد، در src/release/ — برای release. هنگام ساخت، Gradle sourceSet مربوطه را انتخاب کرده و فقط فایلهای آن را کامپایل میکند.
// src/debug/kotlin/com/example/Logger.kt
object Logger {
fun log(tag: String, message: String) {
Log.d(tag, message)
}
}
// src/release/kotlin/com/example/Logger.kt
object Logger {
fun log(tag: String, message: String) {
// No-op در release
}
}
KMP مکانیزم expect (اعلان در کد مشترک) و actual (پیادهسازی برای پلتفرم خاص) را ارائه میدهد. این یک مکانیزم در زمان کامپایل است: برای iOS پیادهسازی actual از iOS sourceSet کامپایل میشود، برای Android — از Android sourceSet. پیادهسازیهای غیرهدف کامپایل نمیشوند.
// commonMain — اعلان expect
expect fun getPlatformName(): String
// androidMain — actual برای Android
actual fun getPlatformName(): String =
"Android \${Build.VERSION.SDK_INT}"
// iosMain — actual برای iOS
actual fun getPlatformName(): String =
UIDevice.current.systemName() + " " + UIDevice.current.systemVersion
در توسعه کتابخانههای بومی از طریق Android NDK از پیشپردازنده کلاسیک C/C++ با دستورالعملهای #ifdef، #ifndef، #define استفاده میشود. برخلاف Swift، پیشپردازنده C در سطح متنی کار میکند — کد در شاخههای غیرفعال میتواند از نظر نحوی نادرست باشد.
NDK ماکروهایی را برای هر پلتفرم تعریف میکند: __ANDROID__ (Android)، __APPLE__ (iOS/macOS)، __linux__ (Linux). برای معماریها: __arm__، __aarch64__، __x86_64__. این ماکروها به طور خودکار توسط کامپایلر هنگام ساخت برای پلتفرم هدف تنظیم میشوند.
// کد بومی برای Android و iOS
#include <cstdint>
#ifdef __ANDROID__
int32_t getJniEnv(JNIEnv* env) {
return env->GetVersion();
}
#elif defined(__APPLE__)
#include <TargetConditionals.h>
int32_t getOsVersion() {
#if TARGET_OS_IOS
return "iOS";
#elif TARGET_OS_OSX
return "macOS";
#endif
}
#endif
هنگام کار با NDK مهم است به خاطر داشته باشید که پیشپردازنده C/C++ یک جایگزینی متنی است. اگر در شاخه غیرفعال خطای نحوی وجود داشته باشد، کامپایلر آن را نمیبیند، اما اگر به دلیل #define نادرست شاخه فعال خراب شود — خطا ظاهر میشود. توصیه میشود زنجیرههای #define را به حداقل برسانید و از ثابتهای constexpr استفاده کنید.
برای Rust، که همچنین در توسعه موبایل از طریق UniFFI و Mozilla Application Services استفاده میشود، مکانیزم خاص خود وجود دارد — feature flags در Cargo.toml. پرچمهایی مانند #[cfg(target_os = "android")] در Rust مشابه دستورالعملهای Swift کار میکنند: بررسی در سطح کامپایلر انجام میشود، نه پیشپردازنده. این باعث میشود Rust انتخاب جذابی برای کتابخانههای بومی باشد که باید از یک پایگاه کد برای Android و iOS کامپایل شوند.
کامپایل شرطی در سناریوهای کاملاً مشخصی مؤثر است. در صورت استفاده نادرست، کد بدبو ایجاد میکند که آزمایش و نگهداری آن دشوار است. بیایید سناریوهای صحیح و اشتباهات معمول را بررسی کنیم.
سناریوی اول — انتزاع پلتفرم: یک نمای واحد که درون آن کامپایل شرطی پیادهسازی پلتفرم را انتخاب میکند. دوم — اشکالزدایی و پروفایلینگ: ابزارهای توسعهدهنده که نباید وارد نسخه نهایی شوند. سوم — سازگاری با نسخههای قبلی: پشتیبانی از نسخههای قدیمی سیستمعامل تا زمانی که حداقل نسخه بهروزرسانی شود.
| سناریو | زبان | شرط |
|---|---|---|
| انتزاع پلتفرم | Swift | #if os(iOS) |
| اشکالزدایی | Swift/ObjC | #if DEBUG |
| سازگاری با نسخههای قبلی | Swift | #if swift(>=5.7) |
| کتابخانه بومی | C/C++ | #ifdef __ANDROID__ |
| آزمایش A/B | Java/Kotlin | BuildConfig.FLAVOR |
خطرناکترین الگوی ضد — گسترش دستورالعملها در سراسر کد. اگر هر فایل دوم حاوی #if باشد، این نشانهای است که معماری نیاز به بازسازی دارد. راهحل صحیح — جدا کردن کد پلتفرم در پشت پروتکلها/رابطها و استفاده از تزریق وابستگی.
سوالات متداول
کامپایل شرطی در مرحله کامپایل کار میکند: کد غیرفعال وارد باینری نمیشود. بررسیهای زمان اجرا (if / switch) همیشه کامپایل میشوند، شرط در زمان اجرا بررسی میشود. اولی ایمنتر و کارآمدتر است، دومی انعطافپذیرتر (قابل تغییر بدون بازسازی).
بله، Swift دستورالعملهای #if داخل توابع، حلقهها و حتی داخل عبارات را مجاز میداند. این یکی از قابلیتهایی است که در نسخههای اولیه Swift وجود نداشت. به عنوان مثال: let x = #if DEBUG 1 #else 0 #endif — کد صحیح.
توسعهدهندگان Kotlin آگاهانه از پیشپردازنده صرفنظر کردند و آن را منبع کد شکننده میدانند. به جای آن، آنها expect/actual (ایمنی زمان کامپایل) و Gradle sourceSets (ایزولهسازی در سطح فایل) را ارائه میدهند. هر دو رویکرد از جایگزینی متنی قابل اعتمادتر هستند.
برنامه را با ترکیبات مختلف پرچمها در CI بسازید. برای Swift: طرحهای جداگانه Xcode با Active Compilation Conditions مختلف تنظیم کنید. برای Android: Build Variants جداگانه تنظیم کرده و برای هر کدام تستها را اجرا کنید. اتوماسیون اجباری است.
در Swift شرط #if یک دستورالعمل کامپایلر است. اگر خود شرط از نظر نحوی نادرست باشد (مثلاً اشتباه تایپی در نام os())، کامپایلر خطای کامپایل صادر میکند. در C/C++ پیشپردازنده به سادگی ماکرو را پیدا نمیکند و شرط نادرست میشود.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.