关于异常捕获那些事

来源:互联网 发布:skype手机聊天软件 编辑:程序博客网 时间:2024/06/15 18:33

iOS提供的异常捕获功能比较简单,它能捕获到一些数据越界,发送方法的错误,但是捕获不到内存级别的错误,网上搜了一个类,捕获这个内存级别的问题,包括友盟都是这么干得,

一篇老外的文章也是介绍异常捕获的情况:http://www.mikeash.com/pyblog/friday-qa-2011-04-01-signal-handling.html

还有C和指针上也有一段关于异常的介绍:Page:338 关于信号的介绍

根据它的说法,当一些异常的信号发生的时候,程序会做出缺省的反应,没有什么标准的缺省的反应,但大部分的编译器都选择了终止应用程序,也就是我们说的程序crash了。我们可以去设置一些信号处理函数,当异常信号发生的时候,我们指定它们帮我们处理一些事情。

据C和指针描述信号处理函数能做的事情非常少: 除了能向一个静态变量赋值外,无法访问其他任何静态数据。


.h文件

#import <Foundation/Foundation.h>


@interface UncaughtExceptionHandler : NSObject

{

   BOOL dismissed;

}


void InstallUncaughtExceptionHandler();


@end


.m文件

#import "UncaughtExceptionHandler.h"

#include <libkern/OSAtomic.h>

#include <execinfo.h>


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 = 0;

const NSInteger UncaughtExceptionHandlerReportAddressCount = 10;

@implementation UncaughtExceptionHandler

void InstallUncaughtExceptionHandler()

{

signal(SIGABRT, MySignalHandler);

signal(SIGILL, MySignalHandler);

signal(SIGSEGV, MySignalHandler);

signal(SIGFPE, MySignalHandler);

signal(SIGBUS, MySignalHandler);

signal(SIGPIPE, MySignalHandler);

}


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

}

}

- (void)handleException:(NSException *)exception


{

    NSLog(@"%@",[[exception userInfo] objectForKey:UncaughtExceptionHandlerAddressesKey]);

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%@",nil),

               [exception reason],

               [[exception userInfo] objectForKey:UncaughtExceptionHandlerAddressesKey]]

      delegate:self

      cancelButtonTitle:NSLocalizedString(@"Quit",nil)

      otherButtonTitles:NSLocalizedString(@"Continue",nil),nil]

    autorelease];

[alert show];

CFRunLoopRef runLoop = CFRunLoopGetCurrent();

CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);

while (!dismissed)

{

for (NSString *modein (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];

}

}

void MySignalHandler(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.\n"@"%@%@",nil),signal, getAppInfo(),callStack]


                                       userInfo:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:signal]

                                                                            forKey:UncaughtExceptionHandlerSignalKey]]waitUntilDone:YES];

}

NSString* getAppInfo()

{

    NSString *appInfo = [NSString stringWithFormat:@"App :%@ %@ %@(%@)\nDevice : %@\nOS Version : %@ %@\nUDID :\n",                         

                         [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"],

                         [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"],

                         [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"],

                         [UIDevice currentDevice].model,

                         [UIDevice currentDevice].systemName,

                         [UIDevice currentDevice].systemVersion,

                         [UIDevice currentDevice].uniqueIdentifier];

    NSLog(@"Crash!!!! %@", appInfo);

    

   return appInfo;

    

}

@end


可以看到是利用了unix底层的一些性能去做了一些处理.