在iOS开发过程中,我们经常要用到NSLog来打印一些调试信息,而且一般是习惯性的大量使用,在模拟器上运行可能没有感觉到什么,但是在真机上,这些NSLog的输出还是比较消耗系统资源的,而且输出的数据有时也可能会暴露出App中的某些私密数据,所以发布正式版时需要把这些输出全部屏蔽掉。
我们可以在发release包之前将这些NSLog统统注释掉,但是如果是大量使用,就有些太过麻烦,而且下次开发时,又需要将注释分别打开继续使用,这样做着实无趣。
下面列举两种较为优雅的方式解决:
1.通过DEBUG条件编译全局控制
因为是全局控制,首先创建pch文件,具体方法较为简单,不过在Xcode6之后注意绑定pch文件的相对路径,这里不再赘述。
创建好之后,在pch文件中添加下列代码:
#ifdef DEBUG
#define DLog(fmt, ...) NSLog((@"[文件名:%s]\n" "[函数名:%s]\n" "[行号:%d] \n" fmt), FILE, FUNCTION, LINE, ##VA_ARGS);
#define DeBugLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), PRETTY_FUNCTION, LINE, ##VA_ARGS);
#define NSLog(...) NSLog(VA_ARGS);
#define MyNSLog(FORMAT, ...) fprintf(stderr,"[%s]:[line %d行] %s\n",[[[NSString stringWithUTF8String:FILE] lastPathComponent] UTF8String], LINE, [[NSString stringWithFormat:FORMAT, ##VA_ARGS] UTF8String]);
#else
#define DLog(...)
#define DeBugLog(...)
#define NSLog(...)
#define MyNSLog(FORMAT, ...)
#endif
上述代码中详细列举了四种较为常用的NSLog的封装,一些事参考了网友的写法,已做实际验证。
补充:
1) VA_ARGS 是一个可变参数的宏,很少人知道这个宏,这个可变参数的宏是新的C99规范中新增的,目前似乎只有gcc支持(VC6.0的编译器不支持)。宏前面加上##的作用在于,当可变参数的个数为0时,这里的##起到把前面多余的","去掉的作用,否则会编译出错, 你可以试试。
2) FILE 宏在预编译时会替换成当前的源文件名
3) LINE宏在预编译时会替换成当前的行号
4) FUNCTION宏在预编译时会替换成当前的函数名称
接下来是DEBUG和release环境的设置:
-
1."Target > Build Settings > Preprocessor Macros > Debug" 里有一个"DEBUG=1",这保证了我们的条件编译的"#if"可以编译。如果没有,请自行添加,注意和代码中的#if后面的字段保持一致。
-
2.环境配置见下图,通过切换Debug和Release,可以控制当前工程的编译环境,当在release环境下时,pch预编译的NSLog相关函数执行是无效的。
2.通过自定义条件编译条件全局控制
这是个人较为偏爱的一种方式,感觉比较灵活。同样在pch文件中添加下面的代码。
- 1.首先自定义全局环境条件编译控制字段
/**
* 工程全局环境控制
*
* 0:开发环境 1:发布环境 2:测试环境
*/
#define MY_PROJECT_GLOBAL_CONTROL 0
上面的0、1、2看个人习惯,只要分得清楚各种环境就行。具体工程的编译环境当然也不局限于上述三类。
在开发或上线时,只要记得修改上述的值以对应于相应的环境就行,当然最好是工程有对应的几个target,这样也就可分别设置,分别使用,不会混淆了。
- 2.同方法1一样,添加下面的代码:
#if (MY_PROJECT_GLOBAL_CONTROL == 0)
#define DLog(fmt, ...) NSLog((@"[文件名:%s]\n" "[函数名:%s]\n" "[行号:%d] \n" fmt), FILE, FUNCTION, LINE, ##VA_ARGS);
#define DeBugLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), PRETTY_FUNCTION, LINE, ##VA_ARGS);
#define NSLog(...) NSLog(VA_ARGS);
#define MyNSLog(FORMAT, ...) fprintf(stderr,"[%s]:[line %d行] %s\n",[[[NSString stringWithUTF8String:FILE] lastPathComponent] UTF8String], LINE, [[NSString stringWithFormat:FORMAT, ##VA_ARGS] UTF8String]);
#elif (MY_PROJECT_GLOBAL_CONTROL == 1)
#define DLog(...)
#define DeBugLog(...)
#define NSLog(...)
#define MyNSLog(FORMAT, ...)
#endif
上述省略了测试环境,测试同开发即可。
这种方式较1更为灵活。对应的条件编译当然也不仅仅局限于NSLog,还有NSAssert或者是对应环境的接口等的设置。
相关Demo已经上传至GitHub,可自行下载参考。
参考文章:
1.在ios iphone编程中使用封装的NSLog来打印调试信息
2.IOS开发之NSLog使用技巧
3.iOS开发中那些高效常用的宏<推荐>
网友评论
#if
#elif
#end
这样更合理吧