__VA_ARGS__ 是一个可变参数的宏,这个可变参数的宏是新的C99规范中新增的,目前似乎只有gcc支持(VC6.0的编译器不支持)。宏前面加上##的作用在于,当可变参数的个数为0时,这里的##起到把前面多余的","去掉的作用,否则会编译出错
__FILE__ %s 宏在预编译时会替换成当前的源文件名,当前源代码文件全路径
__FUNCTION__宏在预编译时会替换成当前的函数名称
__func__%s 当前函数签名
__LINE__ %d 在源代码文件中当前所在行数,宏在预编译时会替换成当前的行号
__PRETTY_FUNCTION__ %s 像 __func__,但是包含了C++代码中的隐形类型信息
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
//连接xcode时可以从监视器中看日志 没连接时Log日志会输出到文件中,
[self redirectNSLogToDocumentFolder];
return YES;
} - (void)redirectNSLogToDocumentFolder
{
//如果已经连接Xcode调试则不输出到文件
// if(isatty(STDOUT_FILENO)) {
// return;
// } // UIDevice *device = [UIDevice currentDevice];
// if([[device model] hasSuffix:@"Simulator"]){ //在模拟器不保存到文件中
// return;
// } //将NSlog打印信息保存到Document目录下的Log文件夹下
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *logDirectory = [[paths objectAtIndex:] stringByAppendingPathComponent:@"Log"]; NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL fileExists = [fileManager fileExistsAtPath:logDirectory];
if (!fileExists) {
[fileManager createDirectoryAtPath:logDirectory withIntermediateDirectories:YES attributes:nil error:nil];
} NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"zh_CN"]];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; //每次启动后都保存一个新的日志文件中
NSString *dateStr = [formatter stringFromDate:[NSDate date]];
NSString *logFilePath = [logDirectory stringByAppendingFormat:@"/%@.log",dateStr]; // 将log输入到文件
freopen([logFilePath cStringUsingEncoding:NSASCIIStringEncoding], "a+", stdout);
freopen([logFilePath cStringUsingEncoding:NSASCIIStringEncoding], "a+", stderr); //未捕获的Objective-C异常日志
NSSetUncaughtExceptionHandler (&UncaughtExceptionHandler);
} void UncaughtExceptionHandler(NSException* exception)
{
NSString* name = [ exception name ];
NSString* reason = [ exception reason ];
NSArray* symbols = [ exception callStackSymbols ]; // 异常发生时的调用栈
NSMutableString* strSymbols = [ [ NSMutableString alloc ] init ]; //将调用栈拼成输出日志的字符串
for ( NSString* item in symbols )
{
[ strSymbols appendString: item ];
[ strSymbols appendString: @"\r\n" ];
} //将crash日志保存到Document目录下的Log文件夹下
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *logDirectory = [[paths objectAtIndex:] stringByAppendingPathComponent:@"Log"]; NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:logDirectory]) {
[fileManager createDirectoryAtPath:logDirectory withIntermediateDirectories:YES attributes:nil error:nil];
} NSString *logFilePath = [logDirectory stringByAppendingPathComponent:@"UncaughtException.log"];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"zh_CN"]];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSString *dateStr = [formatter stringFromDate:[NSDate date]]; NSString *crashString = [NSString stringWithFormat:@"<- %@ ->[ Uncaught Exception ]\r\nName: %@, Reason: %@\r\n[ Fe Symbols Start ]\r\n%@[ Fe Symbols End ]\r\n\r\n", dateStr, name, reason, strSymbols];
//把错误日志写到文件中
if (![fileManager fileExistsAtPath:logFilePath]) {
[crashString writeToFile:logFilePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
}else{
NSFileHandle *outFile = [NSFileHandle fileHandleForWritingAtPath:logFilePath];
[outFile seekToEndOfFile];
[outFile writeData:[crashString dataUsingEncoding:NSUTF8StringEncoding]];
[outFile closeFile];
} //把错误日志发送到邮箱
// NSMutableString *mailUrl = [NSMutableString string];
// [mailUrl appendString:@"mailto:xxxxxxxxx@qq.com"];
// [mailUrl appendString:@"?subject=程序异常崩溃,请配合发送异常报告,谢谢合作!"];
// [mailUrl appendFormat:@"&body=%@", crashString];
// // 打开地址
//// NSString *mailPath = [mailUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
// NSString *mailPath = [mailUrl stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet characterSetWithRange:NSMakeRange(0, mailUrl.length)]];
// [[UIApplication sharedApplication] openURL:[NSURL URLWithString:mailPath]];
}
日志code
在代码中使用Autolayout时,大家都会使用NSDictionaryOfVariableBindings这个宏,这个宏可以生成一个变量名到变量值映射的Dictionary。比如NSDictionaryOfVariableBindings(button1, button2)将会生成一个{ @"button1" = button1, @"button2 = button2 }的Dictionary。它是怎么做到的呢?我们来看看这个宏的定义: #define NSDictionaryOfVariableBindings(...) _NSDictionaryOfVariableBindings(@"" # __VA_ARGS__, __VA_ARGS__, nil)
这个宏定义中有3个参数,后两个参数不难理解,但第一个参数中间有个#符号,语法上看起来比较怪异,这个是什么呢?以前在做越狱的mobilesubstrate开发时,其中定义的一堆宏频繁使用了这个符号,下面就来揭开#这个符号在宏定义中的迷雾。 预编译的一些知识 我们的代码在build时并不是直接进行编译的,在编译之前还进行了预编译处理。预编译会把include或import的文件导入到文件中,同时会将代码中用到的宏进行替换。注意宏是直接在代码中替换成宏的定义的,如果有嵌套也会逐层替换。 “#”指示一些预编译命令 预编译命令一般都是以#开头的,比如#include、#import、#if等,在这里就不一一说明了,本文主要说明一下#在宏定义里面的一些作用。 宏参数字符串化 在一个参数前加一个#,预处理时将会变成这个参数名的字符串常量,即字符串化(stringify)。比如: #define GET_NAME(X) #X
int a = 0;
NSLog(@"%s",GET_NAME(a)); //output: "a"
NSLog(@"%s",GET_NAME(a+)); //output: "a+3"
将会得到以下输出: a
a+
可以看出#,将参数原样转换成字符串常量,如果参数是一个表达式,那么输出这个表达式的原样字符串常量。 回头再看看NSDictionaryOfVariableBindings的定义: #define NSDictionaryOfVariableBindings(...) _NSDictionaryOfVariableBindings(@"" # __VA_ARGS__, __VA_ARGS__, nil)
如果这样生成两个button的映射: NSDictionaryOfVariableBindings(button1, button2);
那么预编译时就会转换成: _NSDictionaryOfVariableBindings(@"""button1, button2", button1, button2, nil);
由于两个常量字符串放在一起就是字符串常量串联,将变成两个字符串常量组合在一起的字符串常量,也就是上面是一个空字符串""和"button1, button2"串联,所以上面的代码等价于: _NSDictionaryOfVariableBindings(@"button1, button2", button1, button2, nil);
那么_NSDictionaryOfVariableBindings函数就可以将它的第一个参数按逗号,分割开作为key,后面就是各个key对应的值了。因此这段代码就创建了一个内容为{ @"button1" = button1, @"button2 = button2 }的Dictionary。 命名的串联 #在宏定义中的另一个作用就是用于命名的串联,用##就可以串联它左右两边的命名,比如以下代码: #define CONCAT(X, Y) X ## Y
NSString *helloworld = @"Hello, world!";
NSLog(@"%@",CONCAT(hello, world)); //output: "Hello, world"
CONCAT(hello, world)实际被转换成helloworld。注意一下,因为宏是预编译阶段进行展开的,就是说在编译之前,因此代码中的hello和world即使没有定义其实也是没问题的,预编译处理后,这两个命名是不存在的。 可选可变参数 ##在宏定义中可以放在__VA_ARGS__之前表示可变参数可以为空,否则的话可变参数至少为一个了。 #define MYLOG(format, ...) NSLog(format, ##__VA_ARGS__)
MYLOG(@"Don't make an error!");
上面代码中MLOG中只有一个参数,如果不加##,则MLOG至少需要两个参数,在Xcode里将会出现编译错误。
#的用法
//将十六进制的字符串转为十进制字符串
+ (NSString *)stringFromHexString:(NSString *)hexString { // char *myBuffer = (char *)malloc((int)[hexString length] / + );
bzero(myBuffer, [hexString length] / + );
for (int i = ; i < [hexString length] - ; i += ) {
unsigned int anInt;
NSString * hexCharStr = [hexString substringWithRange:NSMakeRange(i, )];
NSScanner * scanner = [[NSScanner alloc] initWithString:hexCharStr];
[scanner scanHexInt:&anInt];
myBuffer[i / ] = (char)anInt;
}
NSString *unicodeString = [NSString stringWithCString:myBuffer encoding:];
NSLog(@"------字符串=======%@",unicodeString);
return unicodeString; }
十六进制字符串转为十进制字符串(异常错误处理)
链接:
关于调试日志Log的更多相关文章
-
JMeter-显示调试日志log
JMeter-调试日志记录 参考文档:https://jmeter.apache.org/usermanual/hints_and_tips.html 大多数测试元素包括调试日志记录. 如果从GUI运 ...
-
Expo大作战(六)--expo开发模式,expo中exp命令行工具,expo中如何查看日志log,expo中的调试方式
简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,将全部来与官网 我猜去全部机翻+个人 ...
-
如何正确使用日志Log
title: 如何正确使用日志Log date: 2015-01-08 12:54:46 categories: [Python] tags: [Python,log] --- 文章首发地址:http ...
-
paip.提升效率--调试--日志系统日志参数含义---python
paip.提升效率--调试--日志系统日志参数含义---python #同时向控制台和文件输出日志 #日志参数含义 import logging log_format = '%(filename)s ...
-
【写一个自己的js库】 2.实现自己的调试日志
还是本着学习的目的,实现一个自己的调试日志,界面很简单,就是将调试信息显示在页面的正*,用一个ul包裹,每条信息就是一个li. 1.新建一个myLogger.js文件,将需要的方法声明一下.其中va ...
-
Android开发调试日志工具类[支持保存到SD卡]
直接上代码: package com.example.callstatus; import java.io.File; import java.io.FileWriter; import java.i ...
-
nginx 学习笔记(5) nginx调试日志
为启动一个调试日志,nginx需要在构建时配置城支持调试模式. ./configure --with-debug ... 而且调试级别应该使用err_log指令来设置: err_log /path/t ...
-
在Lua中封装一个调试日志(附lua时间格式)
--自己封装一个Debug调试日志 Debug={} Info={} local function writeMsgToFile(filepath,msg) end function Debug.Lo ...
-
Android输出日志Log类并保存到文件中
android.util.Log常用的方法有以下5个: Log.v() Log.d() Log.i() Log.w() 以及 Log.e().根据首字母分别对应VERBOSE,DEBUG,INFO,W ...
随机推荐
-
BFC给我的帮助以及对hasLayout的认识
布局的时候经常想让一个或几个元素并并排的放在一起,有时给其中的一个浮动,元素是在一行了,可还是都左边重叠了,总是这样那样改来改去,小白的我也是醉了! 今天偶然间看到了了BFC这个东东,虽然现在还是不是 ...
-
php-fpm服务启动脚本
在php-fpm还是打补丁的时候,php-fpm重启只需要执行php-fpm restart或者reload, 自从php5.3之后,php-fpm的启动和停止显得比较麻烦,特意改写了一份nginx的 ...
-
jQuery选择器总结(转)
? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 ...
-
【Android】退出运行了多个Activity的应用
日常开发APP的时候,绝大多数情况下会有多个Activity,而finish()方法只能结束掉一个Activity,那么,我们可以通过什么方法去退出整个Application呢? 根据各大牛的经验,有 ...
-
nginx的conf文件的详细配置
#定义Nginx运行的用户和用户组user www www; #nginx进程数,建议设置为等于CPU总核心数.worker_processes 8; #全局错误日志定义类型,[ debug | in ...
-
如何在同一系统中启动多个 TOMCAT
<Server port="8005" shutdown="SHUTDOWN"> 接受server关闭指令的port号.我们叫关闭指令port. & ...
-
【G】开源的分布式部署解决方案文档 - Web Deploy
G.系列导航 [G]开源的分布式部署解决方案 - 导航 微软官方部署方式 右键项目->发布 这个大家应该再熟悉不过,在部署前有个预览界面可以看本次更新到底更新哪些文件. 既然它可以预览部署结果, ...
-
Android KeyCode 列表
基本按键 KEYCODE_0 按键'0' 7 KEYCODE_1 按键'1' 8 KEYCODE_2 按键'2' 9 KEYCODE_3 按键'3' 10 KEYCODE_4 按键'4' 11 KEY ...
-
homer进行motif分析 ChIP-seq
http://homer.salk.edu/homer/ [怪毛匠子-整理] 使用HOMER分析CLIP-SEQ数据 24 5 2月 2013 | 程序员 Tags: 生物信息学 · 软件 HOM ...
-
Nginx 在ubuntu14.04下的安装
来源:http://blog.csdn.net/hanshileiai/article/details/45580001 按照步骤一步一步来,绝对ok 1.如果出现错误: *4 connect() t ...