• 【IOS】异常捕获 拒绝闪退 让应用从容的崩溃 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);



  • 相关阅读:
    (3)梯度下降法Gradient Descent
    特征工程
    python小笔记
    衡量线性回归法的指标MSE, RMSE,MAE和R Square
    最小二乘法
    最优化原理,凸优化
    线性回归Linear regression
    机器学习流程
    数据归一化Feature Scaling
    kafka重新设置group的offset
  • 原文地址:https://www.cnblogs.com/ldxsuanfa/p/10512533.html
  • Copyright © 2020-2023  润新知