首页 / IOS / iOS 捕获全局异常,统一收集
iOS 捕获全局异常,统一收集
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了iOS 捕获全局异常,统一收集,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含7455字,纯文字阅读大概需要11分钟。
内容图文
参考博文:http://www.cnblogs.com/easonoutlook/archive/2012/12/27/2835979.html
开发程序的过程中不管我们已经如何小心,总是会在不经意间遇到程序闪退。流畅的操作被无情地Crash打断, 当程序运行Crash的时候,系统会把运行的最后时刻的运行信息记录下来,存储到一个文件中,也就是我们所说的Crash文件,当时如果是真机测试离开Xcode的时候Crash掉,我们是无法知道crash的具体位置的。现在做一个程序统一记录crash的位置。先科普一下crash的知识:
Crash文件结构
1、Process Information(进程信息)
Incident Idnetifier | 崩溃报告的唯一标识符,不同的Crash |
CrashReporter Key | 设备标识相对应的唯一键值(并非真正的设备的UDID,苹果为了保护用户隐私iOS6以后已经无法获取)。通常同一个设备上同一版本的App发生Crash时,该值都是一样的。 |
Hardware Model | 代表发生Crash的设备类型,上图中的“iPad4,4”代表iPad Air |
Process | 代表Crash的进程名称,通常都是我们的App的名字, []里面是当时进程的ID |
Path | 可执行程序在手机上的存储位置,注意路径时到XXX.app/XXX,XXX.app其实是作为一个Bundle的,真正的可执行文件其实是Bundle里面的XXX,感兴趣的可以自己查一下相关资料,有机会我后面也会介绍到 |
Identifier | 你的App的Indentifier,通常为“com.xxx.yyy”,xxx代表你们公司的域名,yyy代表某一个App |
Version | 当前App的版本号,由Info.plist中的两个字段组成,CFBundleShortVersionString and CFBundleVersion |
Code Type | 当前App的CPU架构 |
Parent Process | 当前进程的父进程,由于iOS中App通常都是单进程的,一般父进程都是launchd |
2、Basic Information
Date/Time | Crash发生的时间,可读的字符串 |
OS Version | 系统版本,()内的数字代表的时Bulid号 |
Report Version | Crash日志的格式,目前基本上都是104,不同的version里面包含的字段可能有不同 |
3、Exception(非常重要)
Exception Type | 异常类型 |
Exception Subtype: | 异常子类型 |
Crashed Thread | 发生异常的线程号 |
4、Thread Backtrace
发生Crash的线程的Crash调用栈,从上到下分别代表调用顺序,最上面的一个表示抛出异常的位置,依次往下可以看到API的调用顺序。上图的信息表明本次Crash出现xxxViewController的323行,出错的函数调用为orderCountLoadFailed。
5、Thread State
Crash时发生时刻,线程的状态,通常我们根据Crash栈即可获取到相关信息,这部分一般不用关心。
6、Binary Images
Crash时刻App加载的所有的库,其中第一行是Crash发生时我们App可执行文件的信息,可以看出为armv7,可执行文件的包得uuid位c0f……cd65,解析Crash的时候dsym文件的uuid必须和这个一样才能完成Crash的符号化解析。
废话说了那么多,到底怎么捕获整个系统的crash呢,入正题,其实也很简单:创建一个工具类 ExceptionHandler.h 和 ExceptionHandler.m (oc版本),swift版本的下面再讲.
ExceptionHandler.h
#import <UIKit/UIKit.h>
@interface ExceptionHandler : NSObject{
BOOL dismissed;
}
@end
void HandleException(NSException *exception);
void SignalHandler( int signal);
void InstallUncaughtExceptionHandler( void );
ExceptionHandler.m
#import "ExceptionHandler.h"
#include <libkern/OSAtomic.h>
#include <execinfo.h>
NSString * const ExceptionHandlerSignalExceptionName = @"UncaughtExceptionHandlerSignalExceptionName" ;
NSString * const ExceptionHandlerSignalKey = @"UncaughtExceptionHandlerSignalKey" ;
NSString * const ExceptionHandlerAddressesKey = @"UncaughtExceptionHandlerAddressesKey" ;
volatile int32_t UncaughtExceptionCount = 0 ;
const int32_t UncaughtExceptionMaximum = 10 ;
const NSInteger ExceptionHandlerSkipAddressCount = 4 ;
const NSInteger ExceptionHandlerReportAddressCount = 5 ;
@implementation ExceptionHandler
+ (NSArray *)backtrace
{
void * callstack[ 128 ];
int frames = backtrace(callstack, 128 );
char **strs = backtrace_symbols(callstack, frames);
int i;
NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames];
for (
i = ExceptionHandlerSkipAddressCount;
i < ExceptionHandlerSkipAddressCount +
ExceptionHandlerReportAddressCount;
i++)
{
[backtrace addObject:[NSString stringWithUTF8String:strs[i]]];
}
free(strs);
return backtrace;
}
- ( void )alertView:(UIAlertView *)anAlertView clickedButtonAtIndex:(NSInteger)anIndex
{
if (anIndex == 0 )
{
dismissed = YES ;
}
}
- ( void )validateAndSaveCriticalApplicationData
{
}
- ( void )handleException:(NSException *)exception
{
[ self validateAndSaveCriticalApplicationData];
UIAlertView *alert =
[[UIAlertView alloc]
initWithTitle:NSLocalizedString( @"Unhandled exception" , nil )
message:[NSString stringWithFormat:NSLocalizedString(
@"You can try to continue but the application may be unstable.\n\n"
@"Debug details follow:\n%@\n%@" , nil ),
[exception reason],
[[exception userInfo] objectForKey:ExceptionHandlerAddressesKey]]
delegate: self
cancelButtonTitle:NSLocalizedString( @"Quit" , nil )
otherButtonTitles:NSLocalizedString( @"Continue" , nil ), nil ];
[alert show];
NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
CFRunLoopRef runLoop = CFRunLoopGetCurrent();
CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);
while (!dismissed)
{
for (NSString *mode in (NSArray *)allModes)
{
CFRunLoopRunInMode((CFStringRef)mode, 0.001 , false );
}
}
CFRelease(allModes);
NSSetUncaughtExceptionHandler( NULL );
signal(SIGABRT, SIG_DFL);
signal(SIGILL, SIG_DFL);
signal(SIGSEGV, SIG_DFL);
signal(SIGFPE, SIG_DFL);
signal(SIGBUS, SIG_DFL);
signal(SIGPIPE, SIG_DFL);
if ([[exception name] isEqual:ExceptionHandlerSignalExceptionName])
{
kill(getpid(), [[[exception userInfo] objectForKey:ExceptionHandlerSignalKey] intValue]);
}
else
{
[exception raise];
}
}
@end
void HandleException(NSException *exception)
{
int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);
if (exceptionCount > UncaughtExceptionMaximum)
{
return ;
}
NSArray *callStack = [ExceptionHandler backtrace];
NSMutableDictionary *userInfo =
[NSMutableDictionary dictionaryWithDictionary:[exception userInfo]];
[userInfo
setObject:callStack
forKey:ExceptionHandlerAddressesKey];
[[[ExceptionHandler alloc] init]
performSelectorOnMainThread: @selector (handleException:)
withObject:
[NSException
exceptionWithName:[exception name]
reason:[exception reason]
userInfo:userInfo]
waitUntilDone: YES ];
}
void SignalHandler( int signal)
{
int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);
if (exceptionCount > UncaughtExceptionMaximum)
{
return ;
}
NSMutableDictionary *userInfo =
[NSMutableDictionary
dictionaryWithObject:[NSNumber numberWithInt:signal]
forKey:ExceptionHandlerSignalKey];
NSArray *callStack = [ExceptionHandler backtrace];
[userInfo
setObject:callStack
forKey:ExceptionHandlerAddressesKey];
[[[ExceptionHandler alloc] init]
performSelectorOnMainThread: @selector (handleException:)
withObject:
[NSException
exceptionWithName:ExceptionHandlerSignalExceptionName
reason:
[NSString stringWithFormat:
NSLocalizedString( @"Signal %d was raised." , nil ),
signal]
userInfo:
[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:signal] forKey:ExceptionHandlerSignalKey]]
waitUntilDone: YES ];
}
void InstallUncaughtExceptionHandler( void )
{
NSSetUncaughtExceptionHandler(&HandleException);
signal(SIGABRT, SignalHandler);
signal(SIGILL, SignalHandler);
signal(SIGSEGV, SignalHandler);
signal(SIGFPE, SignalHandler);
signal(SIGBUS, SignalHandler);
signal(SIGPIPE, SignalHandler);
}
使用方式:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
InstallUncaughtExceptionHandler();
return YES ;
}
大功告成
swift版本:
func
application(application:
UIApplication
, didFinishLaunchingWithOptions launchOptions: [
NSObject
:
AnyObject
]?) ->
Bool
{
// 输出 bug 信息
print( " 系统 bug 日志记录--------------------- \ ( NSUserDefaults.standardUserDefaults().valueForKey(ERROR_MESSAGE) )" )
NSSetUncaughtExceptionHandler { exception in
var message = exception.callStackSymbols
message.removeAll()
message.append( " 错误理由: \ ( exception.reason! )" )
message.append( " 错误详细信息: \ ( exception.callStackSymbols )" )
NSUserDefaults.standardUserDefaults().setObject(message, forKey: ERROR_MESSAGE)
NSUserDefaults.standardUserDefaults().synchronize()
print( " 系统 bug 日志记录--------------------- \n \ ( message )" )
}
return true
}
swift比oc简单很多,直接在didFinishLaunchingWithOptions加入上面的代码就可以。
测试代码:
NSMutableArray *array = [NSMutableArray array];
[array addObject:@"1"];
[array addObject:@"2"];
NSLog(@"%@",array[9]);
效果图 数组越界:
本文出自 “java” 博客,请务必保留此出处http://5378610.blog.51cto.com/5368610/1861499
原文:http://5378610.blog.51cto.com/5368610/1861499
内容总结
以上是互联网集市为您收集整理的iOS 捕获全局异常,统一收集全部内容,希望文章能够帮你解决iOS 捕获全局异常,统一收集所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。