#ifdef in Swift: How to Replace Conditional Compilation from C/C++

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

"Where is your #ifdef?" — The first question a C developer asks in Swift

\n\n

If you've ever transitioned from C, C++, or Objective-C to Swift, you've probably wondered: "How do I do conditional compilation here? Where is my beloved #ifdef?" This is one of the most popular questions on Stack Overflow — and for good reason. In the world of Swift, there is no preprocessor in the traditional sense, but that doesn't mean you can't flexibly manage builds for different platforms, configurations, or debug modes.

\n\n

In this article, we'll break down the best ways to replace #ifdef in Swift: from simple directives to advanced build schemes. You'll learn how to write code that works on both iOS and macOS, how to hide debug information in release builds, and how not to get confused with platform flags. Let's go!

\n\n

Why Swift doesn't have #ifdef (and that's a good thing)

\n\n

The C preprocessor is a powerful but dangerous tool. It works before the compiler, knows nothing about types or scopes. As a result, it's easy to get a #define that breaks everything around it. Swift developers chose a different path: they built conditional compilation directly into the language, making it safer and more transparent.

\n\n

Instead of #ifdef, you use #if, #elseif, #else, and #endif — the syntax is similar, but it works at the Swift compiler level, not the preprocessor. Plus, they added several built-in flags, which we'll discuss now.

\n\n

Approach 1: Classic #if directives — the closest relative to #ifdef

\n\n

The most direct way is to use #if with predefined conditions:

\n\n
#if DEBUG\n    print("This is a debug build")\n    // Logging, additional checks can go here\n#else\n    print("This is a release build")\n#endif
\n\n

Here is a list of built-in flags you can use:

\n\n
    \n
  • DEBUG — automatically defined for Debug configuration (Xcode adds it automatically)
  • \n
  • os(iOS), os(macOS), os(tvOS), os(watchOS) — platform check
  • \n
  • arch(x86_64), arch(arm64), arch(i386), arch(arm) — processor architecture
  • \n
  • swift(>=5.0) — Swift language version
  • \n
  • canImport(UIKit) — module availability check
  • \n
  • targetEnvironment(simulator) — running on the simulator
  • \n
\n\n

Example of a combined check:

\n\n
#if os(iOS) || os(tvOS)\n    import UIKit\n    typealias PlatformView = UIView\n#elseif os(macOS)\n    import AppKit\n    typealias PlatformView = NSView\n#else\n    typealias PlatformView = Any\n#endif
\n\n

This code creates a single alias for the view class that works on different platforms. Very convenient for cross-platform libraries!

\n\n

Approach 2: Active Compilation Conditions — your own #ifdef

\n\n

What if you need to add your own flag that isn't in the standard set? For example, BETA_FEATURES or PAYMENT_INTEGRATION. For this, Xcode has Active Compilation Conditions.

\n\n

How to configure:

\n
    \n
  1. Open your project in Xcode
  2. \n
  3. Select target → Build Settings → Swift Compiler — Custom Flags
  4. \n
  5. Find the Active Compilation Conditions field
  6. \n
  7. Add your flags separated by spaces, for example: BETA PAYMENT_V2
  8. \n
\n\n

Use it in code like this:

\n\n
#if BETA\n    print("Beta version launched")\n    showBetaUI()\n#endif\n\n#if PAYMENT_V2\n    let paymentProcessor = NewPaymentProcessor()\n#else\n    let paymentProcessor = LegacyPaymentProcessor()\n#endif
\n\n

This is a direct replacement for #ifdef from C/C++! You decide

Blogs

Book Recommendations