#ifdef replacement in the Swift language

前端 未结 17 1718
名媛妹妹
名媛妹妹 2020-11-22 10:35

In C/C++/Objective C you can define a macro using compiler preprocessors. Moreover, you can include/exclude some parts of code using compiler preprocessors.

         


        
相关标签:
17条回答
  • 2020-11-22 11:38

    There is no Swift preprocessor. (For one thing, arbitrary code substitution breaks type- and memory-safety.)

    Swift does include build-time configuration options, though, so you can conditionally include code for certain platforms or build styles or in response to flags you define with -D compiler args. Unlike with C, though, a conditionally compiled section of your code must be syntactically complete. There's a section about this in Using Swift With Cocoa and Objective-C.

    For example:

    #if os(iOS)
        let color = UIColor.redColor()
    #else
        let color = NSColor.redColor()
    #endif
    
    0 讨论(0)
  • 2020-11-22 11:38

    XCODE 9 AND ABOVE

    #if DEVELOP
        //
    #elseif PRODCTN
        //
    #else
        //
    #endif
    
    0 讨论(0)
  • 2020-11-22 11:39

    This builds on Jon Willis's answer that relies upon assert, which only gets executed in Debug compilations:

    func Log(_ str: String) { 
        assert(DebugLog(str)) 
    }
    func DebugLog(_ str: String) -> Bool { 
        print(str) 
        return true
    }
    

    My use case is for logging print statements. Here is a benchmark for Release version on iPhone X:

    let iterations = 100_000_000
    let time1 = CFAbsoluteTimeGetCurrent()
    for i in 0 ..< iterations {
        Log ("⧉ unarchiveArray:\(fileName) memoryTime:\(memoryTime) count:\(array.count)")
    }
    var time2 = CFAbsoluteTimeGetCurrent()
    print ("Log: \(time2-time1)" )
    

    prints:

    Log: 0.0
    

    Looks like Swift 4 completely eliminates the function call.

    0 讨论(0)
  • 2020-11-22 11:41

    Xcode 8 and above

    Use Active Compilation Conditions setting in Build settings / Swift compiler - Custom flags.

    • This is the new build setting for passing conditional compilation flags to the Swift compiler.
    • Simple add flags like this: ALPHA, BETA etc.

    Then check it with compilation conditions like this:

    #if ALPHA
        //
    #elseif BETA
        //
    #else
        //
    #endif
    

    Tip: You can also use #if !ALPHA etc.

    0 讨论(0)
  • 2020-11-22 11:42

    isDebug Constant Based on Active Compilation Conditions

    Another, perhaps simpler, solution that still results in a boolean that you can pass into functions without peppering #if conditionals throughout your codebase is to define DEBUG as one of your project build target's Active Compilation Conditions and include the following (I define it as a global constant):

    #if DEBUG
        let isDebug = true
    #else
        let isDebug = false
    #endif
    

    isDebug Constant Based on Compiler Optimization Settings

    This concept builds on kennytm's answer

    The main advantage when comparing against kennytm's, is that this does not rely on private or undocumented methods.

    In Swift 4:

    let isDebug: Bool = {
        var isDebug = false
        // function with a side effect and Bool return value that we can pass into assert()
        func set(debug: Bool) -> Bool {
            isDebug = debug
            return isDebug
        }
        // assert:
        // "Condition is only evaluated in playgrounds and -Onone builds."
        // so isDebug is never changed to true in Release builds
        assert(set(debug: true))
        return isDebug
    }()
    

    Compared with preprocessor macros and kennytm's answer,

    • ✓ You don't need to define a custom -D DEBUG flag to use it
    • ~ It is actually defined in terms of optimization settings, not Xcode build configuration
    • Documented, which means the function will follow normal API release/deprecation patterns.

    • ✓ Using in if/else will not generate a "Will never be executed" warning.

    0 讨论(0)
提交回复
热议问题