[iOS]异常捕捉

时间:2023-12-29 18:03:02

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 = ;
const int32_t UncaughtExceptionMaximum = ; const NSInteger UncaughtExceptionHandlerSkipAddressCount = ;
const NSInteger UncaughtExceptionHandlerReportAddressCount = ; @interface UncaughtExceptionHandler ()
{
BOOL dismissed;
}
@end @implementation UncaughtExceptionHandler + (NSArray *)backtrace
{
void *callstack[];
int frames = backtrace(callstack, );
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 == )
{
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 = @[@""];
NSLog(@"%@",array[]);
}

运行效果

[iOS]异常捕捉