Active Compilation Conditions ในการพัฒนาแอปพลิเคชัน: แนวคิดหลักและการประยุกต์ใช้

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-06-01 เวลาอ่าน: 8 นาที

Active Compilation Conditions คือแฟล็กที่ส่งให้คอมไพเลอร์ในขั้นตอนการbuild และอนุญาตให้รวมหรือแยกบล็อกโค้ดบางส่วนออกจากไฟล์ไบนารีสุดท้าย ตามเอกสารของ Apple Developer Documentation (2026) Swift รองรับ Active Compilation Conditions ผ่านคีย์ OTHER_SWIFT_FLAGS และคำสั่ง #if Active Compilation Conditions ช่วยให้นักพัฒนาสามารถสร้างโค้ดเวอร์ชันต่างๆ สำหรับการดีบัก การทดสอบ และการผลิตได้โดยไม่ต้องตรวจสอบขณะรันไทม์

ประเด็นสำคัญ

  • Active Compilation Conditions — แฟล็กการคอมไพล์แบบกำหนดเองที่กำหนดว่าบล็อกโค้ดใดจะถูกคอมไพล์ลงในไบนารีสุดท้าย
  • Swift ใช้คีย์ OTHER_SWIFT_FLAGS ในการตั้งค่า Build Settings ของ Xcode เพื่อตั้งค่าแฟล็กด้วยคำนำหน้า -D
  • คำสั่ง #if ตรวจสอบการมีอยู่ของแฟล็ก: โค้ดภายใน #if DEBUG จะถูกคอมไพล์เฉพาะใน build แบบดีบักเท่านั้น
  • Android มีความสามารถที่คล้ายกัน — ฟิลด์ BuildConfig และ productFlavors ใน Gradle
  • ประสิทธิภาพ — การคอมไพล์แบบมีเงื่อนไขไม่ทิ้งร่องรอยในไบนารีรีลีส ซึ่งแตกต่างจากแฟล็กขณะรันไทม์

Active Compilation Conditions คืออะไร

Active Compilation Conditions คือแฟล็กการคอมไพล์ที่กำหนดชุดคำสั่งพรีโปรเซสเซอร์ที่ทำงานอยู่ในขณะbuild ซึ่งแตกต่างจากแฟล็กขณะรันไทม์ (การตรวจสอบ if (isDebug)) เงื่อนไขการคอมไพล์จะแยกโค้ดที่ไม่ทำงานออกจากไฟล์ไบนารีอย่างแท้จริง ส่งผลให้ประสิทธิภาพดีขึ้นและขนาดแอปพลิเคชันลดลง

กลไกทำงานในระดับ พรีโปรเซสเซอร์หรือช่วงต้นของการคอมไพล์: คอมไพเลอร์ได้รับรายชื่อที่ทำงานอยู่ และเมื่อพบคำสั่ง #if NAME จะตรวจสอบว่า NAME อยู่ในรายการนั้นหรือไม่ หากไม่มีชื่อดังกล่าว โค้ดภายในบล็อกจะถูกข้ามและไม่ถูกคอมไพล์

ตามข้อมูลจาก Swift.org Blog (2025) การใช้ Active Compilation Conditions แทนแฟล็กขณะรันไทม์ช่วยลดขนาดไบนารีรีลีสได้เฉลี่ย 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 ไม่ใช่ข้อความที่ถูกแทนที่ ทำให้การดีบักการคอมไพล์แบบมีเงื่อนไขง่ายขึ้นอย่างมาก

Active Compilation Conditions ใน Swift

Swift รองรับ Active Compilation Conditions ผ่านคำสั่ง #if ซึ่งรับรายชื่อแฟล็กที่รวมกับตัวดำเนินการทางตรรกะ &&, || และ ! คอมไพเลอร์จะรวมโค้ดภายใน #if ... #endif เฉพาะเมื่อเงื่อนไขเป็นจริงเท่านั้น

เงื่อนไขในตัวของ Swift

Swift มีเงื่อนไขในตัวหลายอย่าง: DEBUG (ทำงานอัตโนมัติใน build แบบดีบัก), swift(>=5.0) (ตรวจสอบเวอร์ชันคอมไพเลอร์), canImport(UIKit) (ตรวจสอบความพร้อมใช้งานของโมดูล) และ targetEnvironment(simulator) (ตรวจสอบสภาพแวดล้อม) เงื่อนไขเหล่านี้ไม่ต้องการการกำหนดค่าเพิ่มเติม

swift
// เงื่อนไขในตัวของ Swift
#if DEBUG
    print("build แบบดีบัก — การบันทึกทำงาน")
#endif

#if canImport(UIKit)
    import UIKit
    let screen = UIScreen.main.bounds
#elseif canImport(AppKit)
    import AppKit
    let screen = NSScreen.main?.frame
#endif

แฟล็กแบบกำหนดเองใน Xcode

นักพัฒนาสามารถเพิ่มแฟล็กของตนเองผ่านการตั้งค่า Build Setting OTHER_SWIFT_FLAGS ใน Xcode โดยระบุแฟล็กด้วยคำนำหน้า -D เช่น -DBETA หรือ -DANALYTICS_ENABLED สามารถตั้งค่าชุดแฟล็กที่แตกต่างกันสำหรับการกำหนดค่าต่างๆ (Debug, Release, Staging)

swift
// การจัดการแฟล็ก 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
}

เงื่อนไขแพลตฟอร์ม #if os()

Swift รองรับเงื่อนไขแพลตฟอร์ม: os(iOS), os(macOS), os(tvOS), os(watchOS), os(Linux), os(Windows) เงื่อนไขเหล่านี้ตรวจสอบแพลตฟอร์มเป้าหมายของการbuild และอนุญาตให้เขียนโค้ดที่ใช้ร่วมกันระหว่างแพลตฟอร์ม Apple หลายรายการพร้อมบล็อกเฉพาะแพลตฟอร์ม

swift
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 และ Kotlin

ในระบบนิเวศ Android Active Compilation Conditions ถูกนำไปใช้ผ่านระบบ BuildConfig, productFlavors และแฟล็กใน build.gradle.kts Kotlin ไม่มีสิ่งที่เทียบเท่าโดยตรงกับคำสั่ง #if ในระดับภาษาแต่มีกลไกอื่นให้เลือก

ฟิลด์ BuildConfig เป็นแฟล็ก

วิธีที่พบมากที่สุดคือการเพิ่ม buildConfigField สำหรับแต่ละแฟล็ก: buildConfigField("boolean", "BETA", "true") ฟิลด์เหล่านี้จะถูกสร้างขึ้นในคลาส BuildConfig สำหรับแต่ละ Build Variant แยกกัน ฟิลด์ DEBUG มีอยู่ในตัวแล้วและเป็น true โดยอัตโนมัติสำหรับ build แบบดีบัก

kotlin
// build.gradle.kts
android {
    buildTypes {
        debug {
            buildConfigField("boolean", "BETA", "true")
        }
        release {
            buildConfigField("boolean", "BETA", "false")
        }
    }
}

// การใช้งานในโค้ด Kotlin
if (BuildConfig.BETA) {
    enableBetaFeatures()
}

Source Sets และ productFlavors

Gradle อนุญาตให้สร้างไดเรกทอรี sourceSets แยกต่างหากสำหรับแต่ละรสชาติ ตัวอย่างเช่น src/demo/ และ src/full/ คลาสที่มีชื่อเดียวกันใน sourceSets ที่แตกต่างกันจะแทนที่กันเมื่อbuild รสชาติที่เกี่ยวข้อง ซึ่งเป็นกลไกที่ทรงพลังกว่าแฟล็กเพราะสามารถแทนที่คลาสทั้งคลาสได้

kotlin
// 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) และ การอนุญาตสิทธิ์ (เวอร์ชันฟรี/เสียเงิน)

การบันทึกสำหรับดีบัก

สถานการณ์ที่พบบ่อยที่สุดคือการบันทึกแบบมีเงื่อนไข ในbuild แบบดีบัก บันทึกทั้งหมดจะถูกเขียนไปยังคอนโซล; ในbuild แบบรีลีส จะไม่มีการบันทึกอะไรเลย การใช้ #if DEBUG หรือ BuildConfig.DEBUG ช่วยให้มั่นใจได้ว่าไบนารีรีลีสจะไม่มีการเรียก logger แม้แต่ครั้งเดียว รวมถึงที่ถูกอินไลน์

swift
func logRequest(_ url: URL, _ statusCode: Int) {
    #if DEBUG
        Logger.debug("Request to \(url.absoluteString) returned \(statusCode)")
    #endif
}

แฟล็กฟีเจอร์ ณ เวลาbuild

หากฟีเจอร์ใหม่ยังไม่พร้อมสำหรับการผลิต แต่มีอยู่ในโค้ดแล้ว สามารถซ่อนไว้เบื้องหลังแฟล็กการคอมไพล์ได้ แตกต่างจากแฟล็กฟีเจอร์ขณะรันไทม์ แฟล็กการคอมไพล์ไม่สร้างภาระให้แอปพลิเคชันด้วยการตรวจสอบและไม่สามารถเปิดใช้งานโดยผู้ใช้

  • ฟีเจอร์ใหม่ — ซ่อนฟังก์ชันที่ยังไม่เสร็จจนกว่าจะรีลีสครั้งถัดไปโดยไม่ต้องลบโค้ด
  • การวิเคราะห์ — เปิดการเก็บข้อมูลเมตริกเพิ่มเติมเฉพาะสำหรับผู้ทดสอบเบต้า
  • SDK ของบริษัทอื่น — ไม่รวมไลบรารีขนาดใหญ่ออกจากเวอร์ชันฟรีของแอปพลิเคชัน
  • ส่วนประกอบ UI — แสดงหน้าจอทดลองเฉพาะในbuild แบบ staging

แนวทางปฏิบัติที่ดีที่สุด

ควรใช้ Active Compilation Conditions อย่างพอประมาณ จำนวนแฟล็กที่มากเกินไปทำให้โค้ดเข้าใจยาก: นักพัฒนาไม่สามารถแน่ใจได้ว่าสาขาใดจะถูกคอมไพล์ในขณะนั้น ขอแนะนำให้บันทึกแต่ละแฟล็กใน README หรือไฟล์ CONFIG.md โดยเฉพาะ

ในโปรเจกต์ขนาดใหญ่ที่มีทีมกระจายอยู่ทั่วไป การนำ การตรวจสอบแฟล็กอัตโนมัติ ใน CI มาใช้มีประโยชน์มาก ทุกคำขอ pull request ควรผ่านการbuild ด้วยชุดค่าผสมที่เป็นไปได้ทั้งหมดของ Active Compilation Conditions ซึ่งช่วยให้มั่นใจว่าโค้ดภายใต้แฟล็กที่ไม่ทำงานไม่เสียหายจากการปรับโครงสร้าง และไม่มีสาขาการคอมไพล์แบบมีเงื่อนไขใดที่ไม่ถูกทดสอบจนกว่าจะถึงเวลารีลีส เครื่องมือเช่น xcresulttool (สำหรับ iOS) และ Gradle Build Scan (สำหรับ Android) ช่วยทำให้กระบวนการนี้เป็นอัตโนมัติ

  • แฟล็กขั้นต่ำ — ไม่เกิน 5-7 เงื่อนไขที่ทำงานต่อโปรเจกต์ แต่ละแฟล็กคือจุดของความซับซ้อน
  • ธรรมเนียมการตั้งชื่อ — แฟล็กทั้งหมดเป็นตัวพิมพ์ใหญ่ มีคำนำหน้าโปรเจกต์: MYAPP_BETA, MYAPP_ANALYTICS
  • การตรวจสอบโค้ด — การเพิ่ม #if หรือ buildConfigField แต่ละครั้งต้องผ่านการตรวจสอบแยกต่างหาก
  • การทดสอบ — CI ควรbuild ชุดค่าผสมของแฟล็กที่เป็นไปได้ทั้งหมดอย่างน้อยวันละครั้ง

คำถามที่พบบ่อย

ความแตกต่างระหว่าง #if DEBUG และ if (isDebug) ใน Swift คืออะไร?

#if DEBUG คือคำสั่งการคอมไพล์: หาก DEBUG ไม่ทำงาน โค้ดภายในบล็อกจะไม่เข้าไปในไบนารี if (isDebug) คือการตรวจสอบขณะรันไทม์: โค้ดจะถูกคอมไพล์เสมอ เงื่อนไขจะถูกตรวจสอบระหว่างการทำงาน #if ไม่ทิ้งร่องรอยไว้ในbuild แบบรีลีส

ฉันจะเพิ่มแฟล็กแบบกำหนดเองใน Xcode ได้อย่างไร?

ในการตั้งค่า Build Settings ของโปรเจกต์ ค้นหา Other Swift Flags (OTHER_SWIFT_FLAGS) และเพิ่มบรรทัดใหม่ด้วยแฟล็ก: -DMY_FLAG แฟล็กจะปรากฏให้คำสั่ง #if MY_FLAG เห็น สามารถตั้งค่าแฟล็กที่แตกต่างกันสำหรับการกำหนดค่า Debug และ Release

มีสิ่งที่เทียบเท่ากับ Swift #if ใน Kotlin หรือไม่?

Kotlin/JVM ไม่มีสิ่งที่เทียบเท่าโดยตรง แต่จะใช้ ฟิลด์ BuildConfig แทน (การตรวจสอบขณะรันไทม์ แต่ ProGuard อาจลบโค้ดที่ไม่ใช้) ใน Kotlin Multiplatform — คำสั่ง expect/actual ในระดับการประกาศ

สามารถรวมหลายแฟล็กใน #if เดียวกันได้หรือไม่?

ได้ Swift รองรับตัวดำเนินการทางตรรกะ: #if DEBUG && BETA, #if os(iOS) || os(tvOS), #if !RELEASE สามารถจัดกลุ่มเงื่อนไขด้วยวงเล็บสำหรับตรรกะที่ซับซ้อน AND และ OR ทำงานตามกฎ short-circuit มาตรฐาน

ทำไม #if DEBUG ถึงไม่ทำงานในการแสดงตัวอย่าง SwiftUI?

การแสดงตัวอย่าง SwiftUI จะถูกbuild ในกระบวนการแยกต่างหากด้วยแฟล็กที่แตกต่างจากเป้าหมายหลัก DEBUG อาจไม่ทำงาน วิธีแก้ไข: ใช้ targetEnvironment(simulator) สำหรับโค้ดแสดงตัวอย่าง หรือแยกตรรกะแบบมีเงื่อนไขออกเป็นเมธอดแยกต่างหาก

สรุป

  • Active Compilation Conditions — แฟล็กการคอมไพล์ที่แยกโค้ดที่ไม่ทำงานออกจากไบนารีอย่างแท้จริงโดยไม่ต้องตรวจสอบขณะรันไทม์
  • Swift รองรับ #if ด้วยเงื่อนไขในตัว (DEBUG, os, canImport) และแฟล็กแบบกำหนดเองผ่าน OTHER_SWIFT_FLAGS
  • Android และ Kotlin ใช้ฟิลด์ BuildConfig, productFlavors และกลไก expect/actual ใน KMP
  • ประสิทธิภาพ — การคอมไพล์แบบมีเงื่อนไขลดขนาดไบนารีลง 12-18% ในโปรเจกต์ที่มีการบันทึกที่ครอบคลุม
  • แฟล็กฟีเจอร์ ณ เวลาคอมไพล์ไม่สร้างภาระให้แอปพลิเคชันด้วยการตรวจสอบและไม่สามารถเปิดใช้งานโดยผู้ใช้
  • คำแนะนำ — ไม่เกิน 5-7 แฟล็กต่อโปรเจกต์ ธรรมเนียมการตั้งชื่อด้วยคำนำหน้า การทดสอบชุดค่าผสมทั้งหมดใน CI อย่างบังคับ

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม