在开发过程中,我们经常需要用到NSLog输出一些信息,甚至有的开发过程,必须在控制台查看输出,有经验的程序员通过控制台输出就能知道整个数据交互的一个流程。但是一个发布的程序,里面带有太多的NSLog输出,肯定对于App性能有所影响,这时候我们可以使用一个宏定义来处理,在开发的时候使用DEBUG模式,在发布的时候使用RELEASE模式。这样,发布的App就不会在程序内部做大量的NSLog输出了。
简单的代码如下,
1
2
3
4
|
#if defined(DEBUG)||defined(_DEBUG)
NSLog(@
"测试代码"
);
NSLog(@
"Test Coding"
);
#endif
|
上面的#if #endif宏定义的意思就是如果定义了DEBUG,那么就使用NSLog输出;否则这段代码直接忽略。有人会疑问这个DEBUG和_DEBUG来自哪里,这个其实不用担心,这个来自于Xcode的默认设置,我们可以取消DEBUG模式,开启RELEASE发布模式,如下截图所示,
选择Product->Scheme->Edit Scheme,
下图可以选择Debug和Release两种模式,
这里我选择了Release,那么则默认没有定义Debug,则上面代码中#if...#endif之间的输出NSLog不会执行。这样就在发布程序的时候,节省了一些硬件设备的资源。
那么,如何在 Swift 项目里正确地设置 Logging 呢?以下我以 Crashlytics 为例,当然,用其他工具甚至不用第三方工具也是可以的。
在过去 Objective-C 项目里,针对 Development 环境和 Release 环境使用不同的方法进行 Logging 我们是通过 Preprocessor Macros 来进行的。比如 DEBUG 是作为一个默认的 Macro 加进去的:看下图,只要有 $(inherited) 这个在,DEBUG 这个 Macro 就会存在项目的 Development 模式。
那么在 Swift 项目里面我们如何去区分 Debug 和 Release 模式呢?自然也有类似的方式。
实际上,Swift 语言也支持类似于 C 语言一样的 Macro,常用的那些基本能满足我们的使用需求。使在 Swift 项目里也和 Objective-C 一样使用 DEBUG 来区分 Debug 和 Release,我们只需要到 Target 的 Build Settings 里面,找到 Swift Compiler Custom Flags,在 Debug 处传入一个 -D DEBUG 即可。
这样如果你的项目混合了 Objective-C 和 Swift,Objective-C 代码依然会通过之前的 DEBUG 来做正确的分支编译,Swift 编译器也可以通过这个专门的 Custom Flags 来作分支编译。
定义好了这个,我们就可以做正确的 Logging 处理了。
在 AppDelegate.swift (或其他),我做了如下的定义:
import Crashlytics
func NSLog(format: String, args: CVarArgType...) {
#if DEBUG
CLSNSLogv(format, getVaList([]))
#else
CLSLogv(format, getVaList([]))
#endif
}
主要说明:
- CLSNSLogv 是 Crashlytics 提供的,既向终端输出 Log,也会包含在 Crash Log 里面的方法,适合开发用;
- CLSLogv 则是不会向终端输出 Log,但会包含在 Crash log 里的方法,适合 Release 版本用。
于是我在 Swift 代码里重写了 NSLog 这个方法,使其根据不同的编译环境使用不同的 Crashlytics 方法,达到了我预期的效果。
这里还有一点可以改进或讨论的余地,由于 Swift 把 String 的使用变得很方便,我从环境变量构建一个字串再也不用像 Objective-C 那样:
NSLog(@"Hello, this is %@, I'm %d", name, age")
而是直接使用灵巧的 Swift 方式:
NSLog("Hello, this is \(name), I'm \(age)")
因而我用不着 args 部分,只通过 getVaList([]) 传一个空的参数列表进去即可。在实际的使用过程中,这个新包装的 NSLog 也永远也不需要去用到参数列表部分,直接用 Swift 的方式即可。
根据上图,由于我当前是 DEBUG 环境,Xcode 直接高亮了 #if DEBUG 那一块,方便我识别。这样,开发环境中我就可以在终端里看到 Log 输出,而在正式发布的时候它们就不会输出来。我可以像以前一样在项目的其他地方继续用 NSLog,所更改的地方也就是这么一个设置+短短的几行就完成了。
除了因为混合 Objective-C 和 Swift 环境的情况下,我们需要分别设置和确认 Macro/Flag 有没有被设置这点琐碎外,其他我用的还是蛮愉快的。
最后希望正式版早日审核通过 :)