您的位置:首页 > 移动开发 > IOS开发

IOS开发笔记(5)程序异常crash捕获与拦截

2014-02-12 21:08 459 查看
原文地址:点击打开链接

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

一:在.h文件中编写

[plain] view
plaincopy

@interface UncaughtExceptionHandler : NSObject{

BOOL dismissed;

}

@end

void HandleException(NSException *exception);

void SignalHandler(int signal);

void InstallUncaughtExceptionHandler(void);

二:在.m文件编写

[plain] view
plaincopy

#import "UncaughtExceptionHandler.h"

#include <libkern/OSAtomic.h>

#include <execinfo.h>

//http://www.cocoachina.com/newbie/tutorial/2012/0829/4672.html

NSString * const UncaughtExceptionHandlerSignalExceptionName = @"UncaughtExceptionHandlerSignalExceptionName";

NSString * const UncaughtExceptionHandlerSignalKey = @"UncaughtExceptionHandlerSignalKey";

NSString * const UncaughtExceptionHandlerAddressesKey = @"UncaughtExceptionHandlerAddressesKey";

volatile int32_t UncaughtExceptionCount = 0;

const int32_t UncaughtExceptionMaximum = 10;

const NSInteger UncaughtExceptionHandlerSkipAddressCount = 4;

const NSInteger UncaughtExceptionHandlerReportAddressCount = 5;

@implementation UncaughtExceptionHandler

+ (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 = UncaughtExceptionHandlerSkipAddressCount;

i < UncaughtExceptionHandlerSkipAddressCount +

UncaughtExceptionHandlerReportAddressCount;

i++)

{

[backtrace addObject:[NSString stringWithUTF8String:strs[i]]];

}

free(strs);

return backtrace;

}

- (void)alertView:(UIAlertView *)anAlertView clickedButtonAtIndex:(NSInteger)anIndex

{

if (anIndex == 0)

{

dismissed = YES;

}else if (anIndex==1) {

NSLog(@"ssssssss");

}

}

- (void)validateAndSaveCriticalApplicationData

{

}

- (void)handleException:(NSException *)exception

{

[self validateAndSaveCriticalApplicationData];

UIAlertView *alert =

[[[UIAlertView alloc]

initWithTitle:NSLocalizedString(@"抱歉,程序出现了异常", nil)

message:[NSString stringWithFormat:NSLocalizedString(

@"如果点击继续,程序有可能会出现其他的问题,建议您还是点击退出按钮并重新打开\n\n"

@"异常原因如下:\n%@\n%@", nil),

[exception reason],

[[exception userInfo] objectForKey:UncaughtExceptionHandlerAddressesKey]]

delegate:self

cancelButtonTitle:NSLocalizedString(@"退出", nil)

otherButtonTitles:NSLocalizedString(@"继续", nil), nil]

autorelease];

[alert show];

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:UncaughtExceptionHandlerSignalExceptionName])

{

kill(getpid(), [[[exception userInfo] objectForKey:UncaughtExceptionHandlerSignalKey] intValue]);

}

else

{

[exception raise];

}

}

@end

void HandleException(NSException *exception)

{

int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);

if (exceptionCount > UncaughtExceptionMaximum)

{

return;

}

NSArray *callStack = [UncaughtExceptionHandler backtrace];

NSMutableDictionary *userInfo =

[NSMutableDictionary dictionaryWithDictionary:[exception userInfo]];

[userInfo

setObject:callStack

forKey:UncaughtExceptionHandlerAddressesKey];

[[[[UncaughtExceptionHandler alloc] init] autorelease]

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:UncaughtExceptionHandlerSignalKey];

NSArray *callStack = [UncaughtExceptionHandler backtrace];

[userInfo

setObject:callStack

forKey:UncaughtExceptionHandlerAddressesKey];

[[[[UncaughtExceptionHandler alloc] init] autorelease]

performSelectorOnMainThread:@selector(handleException:)

withObject:

[NSException

exceptionWithName:UncaughtExceptionHandlerSignalExceptionName

reason:

[NSString stringWithFormat:

NSLocalizedString(@"Signal %d was raised.", nil),

signal]

userInfo:

[NSDictionary

dictionaryWithObject:[NSNumber numberWithInt:signal]

forKey:UncaughtExceptionHandlerSignalKey]]

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);

}

三:最后在AppDelegate中创建

[plain] view
plaincopy

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

InstallUncaughtExceptionHandler();

self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];

// Override point for customization after application launch.

self.viewController = [[[ViewController alloc] initWithNibName:@"ViewController" bundle:nil] autorelease];

self.window.rootViewController = self.viewController;

[self.window makeKeyAndVisible];

return YES;

}

四:最后的测试

[plain] view
plaincopy

- (IBAction)onclcko:(id)sender {

// [alert show];

NSArray *arry=[NSArray arrayWithObject:@"sss"];

NSLog(@"%@",[arry objectAtIndex:1]);

}

五:结果
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: