在没有预处理宏的情况下,是否有办法在Xcode项目中定义实用的特定方案标志的项目级别?

184
在使用Swift之前,我会为alpha、beta和分发构建定义一组方案。每个方案都会有一组宏,用于在项目级别上控制特定行为。最简单的例子是在默认方案中为所有Xcode项目定义的DEBUG=1宏,用于运行构建。可以通过查询 #ifdef DEBUG ... 并根据代码做出决策,甚至编译掉不必要的代码。
似乎在Swift中,这种配置门控不太容易,因为不支持宏。有人能提出一个类似的方法吗?我并不在乎代码是否被编译掉,但我希望能根据构建方案来控制功能。
7个回答

487
在Swift中,您仍然可以使用"#if/#else/#endif"预处理宏(虽然更受限制),如Apple文档所述。这是一个示例:
#if DEBUG
    let a = 2
#else
    let a = 3
#endif

现在,你必须在其他地方设置“DEBUG”符号。在“Swift编译器 - 自定义标志”部分中的“其他Swift标志”行中设置它。你可以使用-D DEBUG条目添加DEBUG符号。

(构建设置->Swift编译器 - 自定义标志) 输入图像描述

通常情况下,你可以在调试模式或发布模式下设置不同的值。

我已经在实际代码中测试过了;在playground中好像无法识别。


5
请注意,您也可以使用#elseif代码行添加更多的测试。有趣的是,您可以访问定义但不从中提取任何内容;也就是说,定义-DDEBUG=5(或="FOO"),然后尝试使用"println(DEBUG is (DEBUG)"打印它。该行不会生成错误,但也不会执行任何操作。 - David H
10
注意:在“基本”构建设置中,“Built Settings -> Swift Compiler -> Custom Flags”不可见。 必须显示“所有”构建设置才能看到它。 - levibostian
7
可能是因为你需要确保在目标设置中使用 $(inherited) 来继承项目设置。 - DanSkeel
15
在Xcode 8中,“Swift编译器 - 自定义标志”部分现在也有一个“活动编译条件”设置。你可以在此处添加标志,而无需使用“-D”。 - Marcus
2
@JuanFranJimenez,绿色实际上是全局macOS高亮颜色的结果。请在“系统偏好设置”->“常规”中查看。 - wardw
显示剩余8条评论

35

我们遇到了一个问题,不想设置Swift编译器标志,因为我们不想为不同的目标设置并维护它们。此外,在我们混合代码库中,我们不想每次为每种语言都正确地设置标记。

为了解决这个问题,我们在ObjC中声明了一个名为PreProcessorMacros.h的文件。

extern BOOL const DEBUG_BUILD;

在 .m 文件中

PreProcessorMacros.m

#ifdef DEBUG
    BOOL const DEBUG_BUILD = YES;
#else
    BOOL const DEBUG_BUILD = NO;
#endif

然后,在您的Objective-C桥接标头中

#import "PreProcessorMacros.h"

现在,在你的 Swift 代码库中使用它

if DEBUG_BUILD {
    println("debug")
} else {
    println("release")
}

这绝对是一个权宜之计,但它解决了我们的问题,所以我在这里发布它,希望它有所帮助。它并不意味着现有答案是无效的。


13
宏的整个意义在于根据构建配置更改代码。你把if语句带回到了运行时,这并不需要宏。 - Berik
19
@Berik - 我发布了一种有效的解决方案,希望它能帮助其他人解决这个问题的某些方面,特别是在多语言项目中。如果你的问题不需要编译特定的代码,那也没关系。评论也可以,特别是当它教育一些人为什么这可能不是他们的解决方案时。还可以要求在答案中注明这种方法的局限性。否定投票是不必要的,并且会使其他可能有用于解决类似问题的替代解决方案受到打击。此外,问题提出者说:“我不介意代码被编译掉”。 - Logan

6
更加简洁的解决方案是针对Logans方法进行改进。在目标的构建设置中,将Other Swift Flags中的-D DEBUG进行设置。

然后在全局范围内声明以下方法:

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

现在的使用方式为:
if isDebugMode {
    // Do debug stuff
}

5

对于我来说,将“Active Compilation Condition”的调试选项设置为“DEBUG”即可。

在调试模式下,使用 #IF DEBUG 关键字有效,而在发布模式下使用 #ELSE:

  1. Select your target,
  2. In Build Setting tab search for "Active Compilation Condition",
  3. Set the value of its "Debug" item to "YourKeyWord",
  4. Use simply as follow:

    #if DEBUG
        print("You'r running in DEBUG mode!")
    #else
        print("You'r running in RELEASE mode!")
    #endif
    

0

Swift编译器指令

您可以使用下一个编译器指令

#if <some_key>
    //logic 1
#else
    //logic 2
#endif

//pre Xcode v8
Other Swift Flags(OTHER_SWIFT_FLAGS) = -D <some_key>
-D DEBUG

//from Xcode v8
Active Compilation Conditions(SWIFT_ACTIVE_COMPILATION_CONDITIONS) = <some_key>
DEBUG

0
所有都是很好的答案。
我想补充一点,如果你想创建自己更复杂的宏(就像在C++中一样),我建议你研究一下代码片段。
你可以自动完成地输出像这样的东西,并且占位符已经放置好了:
#if DEBUG
<#DEBUGCODE#>
#else
#error("Not for Release!")
#endif

<#DEBUGCODE#> 处生成一个占位符以填充


-1

我正在一个混合语言代码库中工作,其中 obj-c 代码使用宏将调试消息发送到控制台(该宏依赖于我们的调试预处理器标志)。我希望能够在 Swift 代码中调用相同的宏...

  1. 我在我的 obj-c 类之一上创建了一个类方法,该方法是该宏的包装器。
  2. 我将该 obj-c 头文件添加到我们的桥接头文件中。
  3. 现在,我的 Swift 代码将该类方法称为 obj-c 宏的“代理”。

有点烦人的是我不能直接在 Swift 代码中调用宏,但至少现在我只需要关心项目中一个地方来打开/关闭我的调试标志。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接