删除版本iOS Swift的println()
我想全局忽略所有println()
调用在我的Swift代码,如果我不在一个debugging版本。 我找不到任何有力的一步一步的指示,并会赞赏指导。 有没有办法做到这一点在全球范围内,或者我需要用#IF DEBUG/#ENDIF
语句包围每个println()
?
最简单的方法是把你自己的全局函数放在Swift的println
:
func println(object: Any) { Swift.println(object) }
当停止logging的时候,只需注释掉该函数的主体即可:
func println(object: Any) { // Swift.println(object) }
或者你可以通过使用一个条件来使其自动化:
func println(object: Any) { #if DEBUG Swift.println(object) #endif }
在Swift 2.0中编辑 println
被更改为print
。 不幸的是,它现在有一个可变的第一个参数; 这很酷,但这意味着你不能轻易地重写它,因为Swift没有“splat”操作符,所以你不能在代码中传递可变参数(它只能被直接创build)。 但是,如果像通常情况那样只打印一个值,那么可以制作一个缩小版本:
func print(items: Any..., separator: String = " ", terminator: String = "\n") { Swift.print(items[0], separator:separator, terminator: terminator) }
在Swift 3中,你需要抑制第一个参数的外部标签:
func print(_ items: Any..., separator: String = " ", terminator: String = "\n") { Swift.print(items[0], separator:separator, terminator: terminator) }
随着Swift 2.0 / 3.0和Xcode 7/8的testing版本的出现,对于如何在发布版本中禁用打印function进行了一些改变。
上面的@matt和@Nate Birkholz提到的一些重要的点仍然有效。
-
println()
函数已经被print()
-
要使用
#if DEBUG
macros,则必须定义“Swift编译器 – 自定义标志 – 其他标志”以包含值-D DEBUG
-
我build议覆盖全局范围中的
Swift.print()
函数,以便在代码中正常使用print()
函数,但是它将删除非debugging版本的输出。 这是一个函数签名,您可以在全局范围内添加以在Swift 2.0 / 3.0中执行此操作:func print(items: Any..., separator: String = " ", terminator: String = "\n") { #if DEBUG var idx = items.startIndex let endIdx = items.endIndex repeat { Swift.print(items[idx], separator: separator, terminator: idx == (endIdx - 1) ? terminator : separator) idx += 1 } while idx < endIdx #endif }
注意:我们在这里设置了默认的分隔符,并且默认的终止符是一个换行符。 如果你愿意,你可以在你的项目中进行不同的configuration。
希望这可以帮助。
更新:
通常最好把这个函数放在全局范围内,这样它就可以放在Swift的print
函数的前面。 我发现组织这个的最好方法是将一个实用程序文件添加到您的项目中(例如DebugOptions.Swift),您可以将此函数放在全局范围内。
从Swift 3开始, ++
运算符将被弃用。 我已经更新了上面的代码片段来反映这个变化。
包括我在内的所有这些方法的问题在于,它们不会消除评估print
参数的开销。 无论你使用哪一个,这将是昂贵的:
print(myExpensiveFunction())
唯一合适的解决scheme是在条件编译中包装实际的打印调用(让我们假设DEBUG
仅针对debugging版本定义):
#if DEBUG print(myExpensiveFunction()) #endif
只有这样,才能防止在版本构build中调用myExpensiveFunction
。
但是,您可以使用autoclosure将评估推回一级。 因此,你可以重写我的解决scheme(这是Swift 3),如下所示:
func print(_ item: @autoclosure () -> Any, separator: String = " ", terminator: String = "\n") { #if DEBUG Swift.print(item(), separator:separator, terminator: terminator) #endif }
这就解决了这个问题,只是在你打印一件事的时候,通常是这样的。 这是因为在释放模式下不调用item()
。 print(myExpensiveFunction())
因此不再是昂贵的,因为调用被封装在一个闭包中而没有被评估,而在释放模式下,根本不会被评估。
如上所述,我是一个学生,需要更清楚地定义一些东西来跟随。 经过大量的研究,我需要遵循的顺序是:
点击Xcode项目窗口左边文件导航器顶部的项目名称。 这是具有项目名称的行,有多less构build目标以及iOS SDK版本。
selectBuild Settings选项卡,向下滚动到底部附近的“ Swift Compiler – Custom Flags ”部分。 单击其他标志旁边的向下箭头展开该部分。
点击debugging线来select它。 将鼠标光标放在该行的右侧,然后双击。 列表视图将会出现。 点击列表视图左下方的+button添加一个值。 文本字段将变为活动状态。
在文本字段中,input文本-D DEBUG
,然后按Return键提交该行。
将一个新的Swift文件添加到您的项目。 您将要为该文件创build一个自定义类,因此请按以下内容input文本:
class Log { var intFor : Int init() { intFor = 42 } func DLog(message: String, function: String = __FUNCTION__) { #if DEBUG println("\(function): \(message)") #endif } }
我今天无法让Xcode接受这个类,所以init可能会比必要的更重一些。
现在,您将需要在您打算使用新的自定义函数代替println()
任何类中引用您的自定义类。将此作为属性添加到每个适用的类中:
let logFor = Log()
现在可以用logFor.DLog()
replaceprintln()
任何实例。 输出还包含调用该行的函数的名称。
请注意,内部类函数我不能调用该函数,除非我在该类中作为类函数的副本,并且println()
也有一点灵活的input,所以我不能使用它在我的代码中的每个实例。
使用Swift 2.1和Xcode 7.1.1进行testing
一旦知道Swift编译器删除了空的函数 ,就可以轻松地从发行版本中排除所有的打印语句。
注意:在Objective-C的时代,有一个预parsing器可以用来在编译器启动之前删除NSLog语句,就像我在这里回答的那样。 但是由于Swift不再有预parsing器,这种方法不再有效。
这是我今天使用的一种高级的,易于configuration的日志function,而不必担心在发行版本中删除它。 同样,通过设置不同的编译器标志,您可以根据需要调整logging的信息。
你可以根据需要调整function,任何改善它的build议是值得欢迎的!
// Gobal log() function // // note that empty functions are removed by the Swift compiler -> use #if $endif to enclose all the code inside the log() // these log() statements therefore do not need to be removed in the release build ! // // to enable logging // // Project -> Build Settings -> Swift Compiler - Custom flags -> Other Swift flags -> Debug // add one of these 3 possible combinations : // // -D kLOG_ENABLE // -D kLOG_ENABLE -D kLOG_DETAILS // -D kLOG_ENABLE -D kLOG_DETAILS -D kLOG_THREADS // // you can just call log() anywhere in the code, or add a message like log("hello") // func log(message: String = "", filePath: String = #file, line: Int = #line, function: String = #function) { #if kLOG_ENABLE #if kLOG_DETAILS var threadName = "" #if kLOG_THREADS threadName = NSThread.currentThread().isMainThread ? "MAIN THREAD" : (NSThread.currentThread().name ?? "UNKNOWN THREAD") threadName = "[" + threadName + "] " #endif let fileName = NSURL(fileURLWithPath: filePath).URLByDeletingPathExtension?.lastPathComponent ?? "???" var msg = "" if message != "" { msg = " - \(message)" } NSLog("-- " + threadName + fileName + "(\(line))" + " -> " + function + msg) #else NSLog(message) #endif #endif }
这里是你设置编译器标志的地方:
所有标志的输出示例如下所示:
2016-01-13 23:48:38.026 FoodTracker[48735:4147607] -- [MAIN THREAD] ViewController(19) -> viewDidLoad() - hello
log()的代码如下所示:
override func viewDidLoad() { log("hello") super.viewDidLoad() // Handle the text field's user input through delegate callbacks nameTextField.delegate = self }
这是一个我使用的函数,它在Swift 3中完美的工作:
func gLog<T>( _ object: @autoclosure() -> T, _ file: String = #file, _ function: String = #function, _ line: Int = #line) { #if DEBUG let value = object() let stringRepresentation: String if let value = value as? CustomDebugStringConvertible { stringRepresentation = value.debugDescription } else if let value = value as? CustomStringConvertible { stringRepresentation = value.description } else { fatalError("gLog only works for values that conform to CustomDebugStringConvertible or CustomStringConvertible") } let fileURL = NSURL(string: file)?.lastPathComponent ?? "Unknown file" let queue = Thread.isMainThread ? "UI" : "BG" let gFormatter = DateFormatter() gFormatter.dateFormat = "HH:mm:ss:SSS" let timestamp = gFormatter.string(from: Date()) print("✅ \(timestamp) {\(queue)} \(fileURL) > \(function)[\(line)]: " + stringRepresentation + "\n") #endif }
以下是它生成的输出示例:
说明:
-
绿色复选标记用于使您能够快速地在控制台中看到您的打印(gLog)消息,在消息中有时可能会迷失在其他消息的海洋中
-
时间/date戳
-
它正在运行的线程 – 在我的情况下,它可能是MainThread(我称之为UI),或者不是MainThread(我称为BG,用于后台线程)
-
gLog消息所在文件的名称
-
gLog消息所在文件内的function
-
gLog消息的行号
-
您想要打印的实际gLog消息
希望这对其他人有用!
更确切地说,确保-D DEBUG
被设置为OTHER_SWIFT_FLAGS
debugging版本设置:
#if !DEBUG func println(object: Any) {} func print(object: Any){} #endif
在Swift 2 / Xcode 7中,您不再需要/使用println
但是您可能需要为以下内容添加行:
func print(_ items: Any..., separator separator: String = default, terminator terminator: String = default)
XCode 8引入了一些新的构build设置 。
特别是有关“ Active Compilation Conditions
”的内容与其他标志设置的做法相似。
“活动编译条件”是将条件编译标志传递给Swift编译器的新的构build设置。
根据XCode 8(在8.3.2中testing),默认情况下会得到这个:
所以没有任何configuration你可以写下面的内容:
#if DEBUG print("⚠️ Something weird happened") #endif
我强烈build议你,如果你使用这种方法广泛地创build一个包装这个日志逻辑的类/结构/函数。 你可能想要进一步扩展这条路。
你可以定义debug_println
其内容大概是:
#if DEBUG println() #endif
我的解决scheme是在课前在AppDelegate中使用此代码
// Disable console log in live app #if !arch(x86_64) && !arch(i386) public func debugPrint(items: Any..., separator: String = " ", terminator: String = "\n") { } public func print(_ items: Any..., separator: String = " ", terminator: String = "\n") { } #endif class AppDelegate: UIResponder, UIApplicationDelegate { // App Delegate Code }
对于我的解决scheme,我简单一些
import UIKit class DLog: NSObject { init(title:String, log:Any) { #if DEBUG print(title, log) #endif } }
然后显示它只是打电话
_ = DLog(title:"any title", log:Any)
以上都是很好的答案。 您可以简单地使用Swift.debugPrint()
来closures所有打印模式。