【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 : %@ %@(%@)\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);
【IOS】异常捕获 拒绝闪退 让应用从容的崩溃 UncaughtExceptionHandler的更多相关文章
- 异常捕获拒绝闪退 让应用从容的崩溃UncaughtExceptionHandler
虽然大家都不愿意看到程序崩溃,但可能崩溃是每个应用必须面对的现实,既然崩溃已经发生,无法阻挡了,那我们就让它崩也崩得淡定点吧. IOS SDK中提供了一个现成的函数 NSSetUncaughtExce ...
- Unity3D 游戏在 iOS 上因为 trampolines 闪退的原因与解决办法
崩溃的情况 进入游戏一会儿,神马都不要做,双手离开手机,盯着屏幕看吧,游戏会定时从服务器那儿读取一些数据,时间一长,闪退了.尼玛问题是神马呢?完全没有头绪,不过大体猜测是因为网络请求导致的,那么好,先 ...
- Unity3D游戏在iOS上因为trampolines闪退的原因与解决办法
http://7dot9.com/?p=444 http://whydoidoit.com/2012/08/20/unity-serializer-mono-and-trampolines/ 确定具体 ...
- iOS异常捕获
文章目录 一. 系统Crash 二. 处理signal 下面是一些信号说明 关键点注意 三. 实战 四. Crash Callstack分析 – 进⼀一步分析 五. demo地址 六. 参考文献 前言 ...
- 分割视图控制器(UISplitViewController) 改_masterColumnWidth 导致在 IOS 10中出现闪退
默认UISplitViewController的Master和Detail的宽度是固定的,可以通过下面的方式来改变 [splitViewController setValue:[NSNumber nu ...
- #iOS问题记录#WKWebView 闪退异常
异常描述: pointer being freed was not allocated *** set a breakpoint in malloc_error_break to debug 问题描述 ...
- ios 异常捕获
@try { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate c ...
- iOS中app启动闪退的原因
这种情况应和所谓的内存不足关系不大,很少有程序会在初始化时载入大量内容导致崩溃,并且这类问题也很容易在开发阶段被发现,所以内存不足造成秒退的可能性低(内存不足退,通常是程序用了一段时间,切换了几个画面 ...
- iOS异常捕获和处理
2013年4月份整理的代码,仅作记录: //先宏定义 //发布和未发布状态的日志切换 #ifdef DEBUG //异常栈开关 #define STACK_KEY YES ...
随机推荐
- mysql知识点回顾与梳理
一.sql语句执行顺序 from join on where group by avg,sum,count等各种函数 having select distinct order by(asc(升序),d ...
- java 实现文件内容的加密和解密
package com.umapp.test; import java.io.FileInputStream; import java.io.FileOutputStream; import java ...
- 2019-4-6-VisualStudio-编码规范工具-2.6-修改当前文件编码
title author date CreateTime categories VisualStudio 编码规范工具 2.6 修改当前文件编码 lindexi 2019-04-06 15:31:53 ...
- 设置eclipse自动补全
点击" Window>Preferences"; 选择"Java>Editor>Content Assist",在右侧的"Auto- ...
- Laravel使用EasyWechat 进行微信支付
微信支付和EasyWeChat这个包都是巨坑, 文档写的稀烂, 记录下防止以后又重复踩坑: 安装教程在这: https://www.jianshu.com/p/82d688e1fd2a
- H5C3--盒子模型
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 记录centos7下tomcat部署war包过程
记录centos7下tomcat部署war包过程 1.官网下载tomcat安装包.gz结尾的 2.上传到/usr/local/ ,并解压到tomcat目录下 3.进入tomcat/bin目录,运行./ ...
- python学生管理系统
import osimport re #获取本机用户名,构建student.txt文件名创建在左面import getpassusername=getpass.getuser()print(" ...
- 提升mysql服务器性能(索引与查询优化)
原文:提升mysql服务器性能(索引与查询优化) 版权声明:皆为本人原创,复制必究 https://blog.csdn.net/m493096871/article/details/90138407 ...
- 洛谷P2835 刻录光盘 [2017年6月计划 强连通分量02]
P2835 刻录光盘 题目描述 在JSOI2005夏令营快要结束的时候,很多营员提出来要把整个夏令营期间的资料刻录成一张光盘给大家,以便大家回去后继续学习.组委会觉得这个主意不错!可是组委会一时没有足 ...