欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

[iOS]异常捕捉

程序员文章站 2022-06-30 19:32:27
UncaughtExceptionHandler.h UncaughtExceptionHandler.m 开启异常捕捉 异常示例 运行效果 ......

uncaughtexceptionhandler.h

#import <foundation/foundation.h>

ns_assume_nonnull_begin

@interface uncaughtexceptionhandler : nsobject

@end

void uncaughtexceptionhandlerstart(void);

ns_assume_nonnull_end

uncaughtexceptionhandler.m

#import "uncaughtexceptionhandler.h"
#import <uikit/uikit.h>
#import <libkern/osatomic.h>
#import <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;

@interface uncaughtexceptionhandler ()
{
    bool dismissed;
}
@end

@implementation uncaughtexceptionhandler

+ (nsarray *)backtrace
{
    void *callstack[128];
    int frames = backtrace(callstack, 128);
    char **strs = backtrace_symbols(callstack, frames);
    
    nsmutablearray *backtrace = [nsmutablearray arraywithcapacity:frames];
    int end = uncaughtexceptionhandlerskipaddresscount + uncaughtexceptionhandlerreportaddresscount;
    
    for (int i = uncaughtexceptionhandlerskipaddresscount;i < end;i++)
    {
        [backtrace addobject:[nsstring stringwithutf8string:strs[i]]];
    }
    free(strs);
    
    return backtrace;
}

- (void)handleexception:(nsexception *)exception
{
    nsstring *reason = [exception reason];
    nsstring *addresses = [[exception userinfo] objectforkey:uncaughtexceptionhandleraddresseskey];
    uialertview *alert = [[uialertview alloc] initwithtitle:@""
                                                    message:[nsstring stringwithformat:@"reason:%@\n addresses:%@",reason,addresses]
                                                   delegate:self
                                          cancelbuttontitle:@"退出"
                                          otherbuttontitles:@"继续", nil];
    [alert show];
    
    cfrunloopref runloop = cfrunloopgetcurrent();
    cfarrayref allmodes = cfrunloopcopyallmodes(runloop);
    
    while (!dismissed)
    {
        for (nsstring *mode in (__bridge 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)alertview:(uialertview *)analertview clickedbuttonatindex:(nsinteger)anindex
{
    if (anindex == 0)
    {
        dismissed = yes;
    }
}

@end

void handleexception(nsexception *exception);
void signalhandler(int signal);

void uncaughtexceptionhandlerstart(void)
{
    nssetuncaughtexceptionhandler(&handleexception);
    signal(sigabrt, signalhandler);
    signal(sigill, signalhandler);
    signal(sigsegv, signalhandler);
    signal(sigfpe, signalhandler);
    signal(sigbus, signalhandler);
    signal(sigpipe, signalhandler);
}

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] 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] performselectoronmainthread:@selector(handleexception:)
                                                              withobject:[nsexception exceptionwithname:uncaughtexceptionhandlersignalexceptionname
                                                                                                 reason:[nsstring stringwithformat:@"signal %d was raised.",signal]
                                                                                               userinfo:[nsdictionary dictionarywithobject:[nsnumber numberwithint:signal]
                                                                                                                                    forkey:uncaughtexceptionhandlersignalkey]]
                                                           waituntildone:yes];
}

开启异常捕捉

#import "appdelegate.h"
#import "uncaughtexceptionhandler.h"

@interface appdelegate ()

@end

@implementation appdelegate

- (bool)application:(uiapplication *)application didfinishlaunchingwithoptions:(nsdictionary *)launchoptions
{
    // override point for customization after application launch.
    
    uncaughtexceptionhandlerstart();
    
    return yes;
}

异常示例

- (void)touchesbegan:(nsset<uitouch *> *)touches withevent:(uievent *)event
{
    nsarray *array = @[@"1"];
    nslog(@"%@",array[5]);
}

运行效果

[iOS]异常捕捉