zoukankan      html  css  js  c++  java
  • 异常捕获拒绝闪退 让应用从容的崩溃UncaughtExceptionHandler

    虽然大家都不愿意看到程序崩溃,但可能崩溃是每个应用必须面对的现实,既然崩溃已经发生,无法阻挡了,那我们就让它崩也崩得淡定点吧。

    IOS SDK中提供了一个现成的函数 NSSetUncaughtExceptionHandler 用来做异常处理,但功能非常有限,而引起崩溃的大多数原因如:内存访问错误,重复释放等错误就无能为力了,因为这种错误它抛出的是Signal,所以必须要专门做Signal处理。首先定义一个UncaughtExceptionHandler类,代码如下:

     

    #import <Foundation/Foundation.h>

    #import <UIKit/UIKit.h>

    @interface UncaughtExceptionHandler : NSObject

    {

        BOOL dismissed;

    }

    +(void) InstallUncaughtExceptionHandler;

    @end

    //利用 NSSetUncaughtExceptionHandler,当程序异常退出的时候,可以先进行处理,然后做一些自定义的动作,比如下面一段代码,就是网上有人写的,直接在发生异常时给某人发送邮件,</span>

    void UncaughtExceptionHandlers (NSException *exception);

    #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 = 4;

    const NSInteger UncaughtExceptionHandlerReportAddressCount = 5;

    NSString* getAppInfo()

    {

        NSString *appInfo = [NSString stringWithFormat:@"App : %@ %@(%@) Device : %@ OS Version : %@ %@ ",

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

    }

     

     

    void MySignalHandler(int signal)

    {

      int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);

      if (exceptionCount > UncaughtExceptionMaximum)

      {

        return;

      }

        if(signal==11)

        {//比较坑爹的是 我遇到的一个问题只有iPhone5出现问题 但是我这边测试的没有iPhone5 无法直接log  可能是内存不足 果然 删除几个应用就可以了 所以加了这句

    UIAlertView * tip2 = [[UIAlertView alloc]initWithTitle:@"可能原因:key" message:@"内存不足" delegate:nil cancelButtonTitle:@"ok" otherButtonTitles:nil];

            [tip2 show];

            [tip2 release];

        }

      

        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, getAppInfo()]

          userInfo:

          [NSDictionary

           dictionaryWithObject:[NSNumber numberWithInt:signal]

           forKey:UncaughtExceptionHandlerSignalKey]]

         waitUntilDone:YES];

     

    }

     

     

    @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

    {

      UIAlertView *alert =

        [[[UIAlertView alloc]

          initWithTitle:NSLocalizedString(@"Unhandled exception", nil)

          message:[NSString stringWithFormat:NSLocalizedString(

            @"You can try to continue but the application may be unstable. "

            @"%@ %@", 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 *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];

      }

    }

    void UncaughtExceptionHandlers (NSException *exception) {

        NSArray *arr = [exception callStackSymbols];

        NSString *reason = [exception reason];

        NSString *name = [exception name];

        NSString *urlStr = [NSString stringWithFormat:@"mailto://1140454645@qq.com?subject=bug报告&body=感谢您的配合!<br><br><br>"

                            "错误详情:<br>%@<br>--------------------------<br>%@<br>---------------------<br>%@",

                            name,reason,[arr componentsJoinedByString:@"<br>"]];

        NSURL *url = [NSURL URLWithString:[urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

        [[UIApplication sharedApplication] openURL:url];

        

        //或者直接用代码,输入这个崩溃信息,以便在console中进一步分析错误原因

        NSLog(@"1heqin, CRASH: %@", exception);

        NSLog(@"heqin, Stack Trace: %@", [exception callStackSymbols]);

    }

     

    @end

    然后在delegate文件里面- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions函数里面

    [UncaughtExceptionHandler InstallUncaughtExceptionHandler];

        NSSetUncaughtExceptionHandler (&UncaughtExceptionHandlers);

  • 相关阅读:
    UVA 11925 Generating Permutations 生成排列 (序列)
    UVA 1611 Crane 起重机 (子问题)
    UVA 11572 Unique snowflakes (滑窗)
    UVA 177 PaperFolding 折纸痕 (分形,递归)
    UVA 11491 Erasing and Winning 奖品的价值 (贪心)
    UVA1610 PartyGame 聚会游戏(细节题)
    UVA 1149 Bin Packing 装箱(贪心)
    topcpder SRM 664 div2 A,B,C BearCheats , BearPlays equalPiles , BearSorts (映射)
    UVA 1442 Cave 洞穴 (贪心+扫描)
    UVA 1609 Foul Play 不公平竞赛 (构(luan)造(gao)+递归)
  • 原文地址:https://www.cnblogs.com/zxykit/p/5157894.html
Copyright © 2011-2022 走看看