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

iOS程序异常crash捕获与拦截

2014-07-28 11:46 453 查看
开发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]);  

}  

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