Answers:
是的,你可以做到。
在Swift中,按照Apple docs的规定,您仍然可以使用“#if /#else /#endif”预处理器宏(尽管有更多限制)。这是一个例子:
#if DEBUG
let a = 2
#else
let a = 3
#endif
现在,您必须在其他位置设置“ DEBUG”符号。在“ Swift编译器-自定义标志”部分的“其他Swift标志”行中进行设置。您将DEBUG符号与-D DEBUG
条目中。
与往常一样,您可以在Debug或Release中设置不同的值。
我用真实代码对其进行了测试,并且可以正常工作。它似乎在操场上似乎未被认可。
您可以在这里阅读我的原始帖子。
重要说明: -DDEBUG=1
不起作用。仅-D DEBUG
适用。似乎编译器正在忽略具有特定值的标志。
-D DEBUG
上述添加之外,您还需要DEBUG=1
在Apple LLVM 6.0 - Preprocessing
->中定义Preprocessor Macros
。
-DDEBUG
为以下答案之前,我无法使它起作用:stackoverflow.com/a/24112024/747369。
DEBUG=1
到Preprocessor Macros
,如果你不想在Objective-C代码来使用它。
Swift编译器不包含预处理器。相反,它利用编译时属性,构建配置和语言功能来实现相同的功能。因此,预处理器指令不会导入Swift中。
通过使用自定义构建配置,我设法实现了想要的目标:
检查目标的方法如下:
#if BANANA
print("We have a banana")
#elseif MELONA
print("Melona")
#else
print("Kiwi")
#endif
使用Swift 2.2测试
-DLOCAL
,在我的#if LOCAl #else #endif
,它落入#else
部分。我复制了原始目标AppTarget
并将其重命名为AppTargetLocal
&设置其自定义标志。
#if LOCAL
,当我使用模拟器运行并#else
在测试过程中,它落入了预期的结果。我希望它#if LOCAL
在测试过程中也能适用。
在很多情况下,您实际上并不需要条件编译;您只需要可以打开和关闭的条件行为即可。为此,您可以使用环境变量。这具有巨大的优势,您实际上不必重新编译。
您可以在方案编辑器中设置环境变量,并轻松地将其打开或关闭:
您可以使用NSProcessInfo检索环境变量:
let dic = NSProcessInfo.processInfo().environment
if dic["TRIPLE"] != nil {
// ... do secret stuff here ...
}
这是一个真实的例子。我的应用程序仅在设备上运行,因为它使用的音乐库在模拟器上不存在。那么,如何在模拟器上为我不拥有的设备拍摄屏幕截图?没有这些屏幕截图,我将无法提交到AppStore。
我需要伪造数据和其他处理方式。我有两个环境变量:一个在打开时告诉应用程序在设备上运行时从真实数据生成假数据;另一种是在模拟器上运行时打开时使用伪造的数据(而不是缺少的音乐库)。通过使用方案编辑器中的环境变量复选框,可以轻松打开/关闭这些特殊模式。而且好处是,我不会在App Store构建中意外使用它们,因为归档没有环境变量。
ifdef
Xcode 8提出了一项重大的替换变更,即使用Active Compilation Conditions。
请参阅建筑及链接在Xcode中8注版。
新的构建设置
新设定: SWIFT_ACTIVE_COMPILATION_CONDITIONS
“Active Compilation Conditions” is a new build setting for passing conditional compilation flags to the Swift compiler.
以前,我们必须在OTHER_SWIFT_FLAGS下声明您的条件编译标志,记住要在该设置之前加上“ -D”。例如,要有条件地使用MYFLAG值进行编译:
#if MYFLAG1
// stuff 1
#elseif MYFLAG2
// stuff 2
#else
// stuff 3
#endif
要添加到设置的值 -DMYFLAG
现在我们只需要将值MYFLAG传递给新设置。现在该移动所有这些条件编译值了!
请参考以下链接,了解Xcode 8中更多的Swift Build设置功能:http : //www.miqu.me/blog/2016/07/31/xcode-8-new-build-settings-and-analyzer-improvements/
从Swift 4.1开始,如果只需要检查代码是使用调试还是发布配置构建的,则可以使用内置函数:
_isDebugAssertConfiguration()
(当优化设置为时为true -Onone
)_isReleaseAssertConfiguration()
(当优化设置为时为true -O
)_isFastAssertConfiguration()
(当优化设置为时为true -Ounchecked
)例如
func obtain() -> AbstractThing {
if _isDebugAssertConfiguration() {
return DecoratedThingWithDebugInformation(Thing())
} else {
return Thing()
}
}
与预处理器宏相比,
-D DEBUG
标志即可使用它✗未记录,这意味着该功能可以在任何更新中删除(但它应该是AppStore安全的,因为优化程序会将其转换为常量)
@testable
属性而重新回归,命运对未来的Swift不确定。in在in / if / else中使用将始终生成“将永远不会执行”警告。
if _isDebugAssertConfiguration()
将被评估为if false
处于释放模式,并且处于if true
调试模式。
没有Swift预处理器。(一方面,任意代码替换都会破坏类型和内存安全性。)
不过,Swift确实包含了构建时配置选项,因此您可以有条件地包含某些平台或构建样式的代码,或者响应您使用-D
编译器args 定义的标志。但是,与C语言不同,代码的条件编译部分必须在语法上完整。在Swift与Cocoa和Objective-C结合使用中有关于这一部分的内容。
例如:
#if os(iOS)
let color = UIColor.redColor()
#else
let color = NSColor.redColor()
#endif
INT_CONST
a 放置在任何float
可接受的位置。Swift不允许这样做。此外,如果您var floatVal = INT_CONST
不可避免地要这样做,则稍后在编译器期望an时,它将在某处崩溃,Int
但您将其用作Float
(类型floatVal
将被推断为Int
)。10次转换之后,它更干净了,可以删除宏...
另一个可能更简单的解决方案仍然#if
定义DEBUG
为您的项目构建目标之一,Active Compilation Conditions
并包含以下内容(我将其定义为全局常量):
#if DEBUG
let isDebug = true
#else
let isDebug = false
#endif
这个概念建立在肯尼TM的答案之上
与kennytm相比,它的主要优点是,它不依赖于私有或未记录的方法。
在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
}()
与预处理器宏和kennytm的答案相比,
-D DEBUG
标志即可使用它✓已记录,这意味着该功能将遵循正常的API发布/弃用模式。
✓在if / else中使用in 不会产生“永远不会执行”警告。
Moignans 在这里的回答很好。如果有帮助,这里还有另一条信息,
#if DEBUG
let a = 2
#else
let a = 3
#endif
您可以像下面那样否定宏,
#if !RELEASE
let a = 2
#else
let a = 3
#endif
在使用Xcode 9.4.1创建的Swift项目中,Swift 4.1
#if DEBUG
#endif
默认情况下有效,因为Xcode已经在Preprocessor Macros中设置了DEBUG = 1。
因此,您可以使用#if DEBUG“开箱即用”。
顺便说一句,如何在Apple的书《 Swift编程语言4.1》(“编译器控制语句”部分)中编写了一般如何使用条件编译块的方法,以及如何编写编译标志以及Swift中C宏的对应内容的内容。苹果公司的另一本书《将Swift与Cocoa和Objective C结合使用(在Preprocessor Directives部分中)
希望将来苹果能为他们的书写出更详细的内容和索引。
设置完成后DEBUG=1
您的GCC_PREPROCESSOR_DEFINITIONS
生成设置我更喜欢使用的功能,使这个电话:
func executeInProduction(_ block: () -> Void)
{
#if !DEBUG
block()
#endif
}
然后只需将我要在Debug版本中省略的任何块包含在此函数中:
executeInProduction {
Fabric.with([Crashlytics.self]) // Compiler checks this line even in Debug
}
相比于以下优势:
#if !DEBUG
Fabric.with([Crashlytics.self]) // This is not checked, may not compile in non-Debug builds
#endif
是编译器检查我的代码的语法,所以我确定它的语法正确并且可以构建。
这是基于Jon Willis的依赖断言的答案而建立的,仅在Debug编译中执行:
func Log(_ str: String) {
assert(DebugLog(str))
}
func DebugLog(_ str: String) -> Bool {
print(str)
return true
}
我的用例是记录打印语句。这是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)" )
印刷品:
Log: 0.0
看起来Swift 4完全消除了函数调用。