可见的异常

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

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 : %@ %@(%@)\nDevice : %@\nOS Version : %@ %@\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;  
}  
  
  
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.\n"  
                         @"%@", 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.\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 *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);  
原文:http://blog.csdn.net/yhhwatl/article/details/34432603?utm_source=tuicool#comments

  1.         


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值