现在的位置: 首页 > 综合 > 正文

NSNotificationCenter 编写日志组件

2018年09月10日 ⁄ 综合 ⁄ 共 1745字 ⁄ 字号 评论关闭

开发iOS应用,解决Crash问题始终是一个难题。Crash分为两种,一种是由EXC_BAD_ACCESS引起的,原因是访问了不属于本进程的内存地址,有可能是访问已被释放的内存;另一种是未被捕获的Objective-C异常(NSException),导致程序向自身发送了SIGABRT信号而崩溃。其实对于未捕获的Objective-C异常,我们是有办法将它记录下来的,如果日志记录得当,能够解决绝大部分崩溃的问题。这里对于UI线程与后台线程分别说明。

先看UI线程。iOS SDK提供了NSSetUncaughtExceptionHandler函数,用法如:

NSSetUncaughtExceptionHandler( handleRootException );

这样在UI线程发生未捕获异常后,进程崩溃之前,handleRootException会被执行。这个函数实现如下

复制代码
static void handleRootException( 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" ];
}

// 写日志,级别为ERROR
writeCinLog( __FUNCTION__, CinLogLevelError, @"[ Uncaught Exception ]\r\nName: %@, Reason: %@\r\n[ Fe Symbols Start ]\r\n%@[ Fe Symbols End ]", name, reason, strSymbols );
[ strSymbols release ];

// 这儿必须Hold住当前线程,等待日志线程将日志成功输出,当前线程再继续运行
blockingFlushLogs( __FUNCTION__ );

// 写一个文件,记录此时此刻发生了异常。这个挺有用的哦
NSDictionary* dict = [ NSDictionary dictionaryWithObjectsAndKeys:
currentCinLogFileName(), @"LogFile", // 当前日志文件名称
currentCinLogFileFullPath(), @"LogFileFullPath", // 当前日志文件全路径
[ NSDate date ], @"TimeStamp", // 异常发生的时刻
nil ];
NSString* path = [ NSString stringWithFormat: @"%@/Documents/", NSHomeDirectory() ];
NSString* lastExceptionLog = [ NSString stringWithFormat: @"%@LastExceptionLog.txt", path ];
[ dict writeToFile: lastExceptionLog atomically: YES ];

}
复制代码

而我们的日志组件必须实现blockingFlushLogs函数,确保进程在日志完全写入文件后再退出。这个实现应该很简单吧。

当应用下次启动时,我们可以检查,如果有LastExceptionLog.txt,则弹窗引导测试人员将日志发过来。如果iPhone上面配置了EMail帐户,可以很简单的调用MFMailComposeViewController将日志文件作为附件发送,当然也可以想其它办法。

记得正式发布的版本要将它条件编译去掉哦。

其中文件中的最后一条ERROR即为导致崩溃的异常,而从ERROR之前的日志可以看出当前程序的运行情况。

来自:http://www.cnblogs.com/alario/archive/2012/03/28/2421574.html

抱歉!评论已关闭.