IOS应用崩溃复活
时间:2021-09-06
本文章向大家介绍IOS应用崩溃复活,主要包括IOS应用崩溃复活使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
IOS应用崩溃一直是一个很苦恼的问题,而崩溃的同时又未获取bug原因,更令人苦恼。
好在苹果自带的crash检测api,以及runloop可以让应用复活一次,不过第二次依旧会崩溃,但是还是一个很实用的小技巧。
以下是IOS崩溃复活的类和使用方法
#import "CrashHandler.h"
//Appdelagte中注册crash记录上报
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
[CrashHandler sharedInstance];
return YES;
}
//.h文件
#import <Foundation/Foundation.h>
@interface CrashHandler : NSObject
{
BOOL ignore;
}
+ (instancetype)sharedInstance;
@end
//.m文件
#import "CrashHandler.h"
#import <UIKit/UIKit.h>
#include <libkern/OSAtomic.h>
#include <execinfo.h>
NSString * const kSignalExceptionName = @"kSignalExceptionName";
NSString * const kSignalKey = @"kSignalKey";
NSString * const kCaughtExceptionStackInfoKey = @"kCaughtExceptionStackInfoKey";
void HandleException(NSException *exception);
void SignalHandler(int signal);
@implementation CrashHandler
static CrashHandler *instance = nil;
+ (instancetype)sharedInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[[self class] alloc] init];
});
return instance;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [super allocWithZone:zone];
});
return instance;
}
- (instancetype)init
{
self = [super init];
if (self) {
[self setCatchExceptionHandler];
}
return self;
}
- (void)setCatchExceptionHandler
{
// 1.捕获一些异常导致的崩溃
NSSetUncaughtExceptionHandler(&HandleException);
// 2.捕获非异常情况,通过signal传递出来的崩溃
signal(SIGABRT, SignalHandler);
signal(SIGILL, SignalHandler);
signal(SIGSEGV, SignalHandler);
signal(SIGFPE, SignalHandler);
signal(SIGBUS, SignalHandler);
signal(SIGPIPE, SignalHandler);
}
+ (NSArray *)backtrace
{
void* callstack[128];
int frames = backtrace(callstack, 128);
char **strs = backtrace_symbols(callstack, frames);
NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames];
for (int i = 0; i < frames; i++) {
[backtrace addObject:[NSString stringWithUTF8String:strs[i]]];
}
free(strs);
return backtrace;
}
- (void)alertView:(UIAlertView *)anAlertView clickedButtonAtIndex:(NSInteger)anIndex
{
if (anIndex == 0) {
ignore = YES;
} else if (anIndex == 1) {
NSLog(@"起死回生");
}
}
- (void)handleException:(NSException *)exception
{
NSString *message = [NSString stringWithFormat:@"崩溃原因如下:\n%@\n%@",
[exception reason],
[[exception userInfo] objectForKey:kCaughtExceptionStackInfoKey]];
NSLog(@"%@",message);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"程序崩溃了"
message:@"如果你能让程序起死回生,那你的决定是?"
delegate:self
cancelButtonTitle:@"崩就蹦吧"
otherButtonTitles:@"起死回生", nil];
[alert show];
CFRunLoopRef runLoop = CFRunLoopGetCurrent();
CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);
while (!ignore) {
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:kSignalExceptionName]) {
kill(getpid(), [[[exception userInfo] objectForKey:kSignalKey] intValue]);
} else {
[exception raise];
}
}
@end
void HandleException(NSException *exception)
{
// 获取异常的堆栈信息
NSArray *callStack = [exception callStackSymbols];
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
[userInfo setObject:callStack forKey:kCaughtExceptionStackInfoKey];
CrashHandler *crashObject = [CrashHandler sharedInstance];
NSException *customException = [NSException exceptionWithName:[exception name] reason:[exception reason] userInfo:userInfo];
[crashObject performSelectorOnMainThread:@selector(handleException:) withObject:customException waitUntilDone:YES];
}
void SignalHandler(int signal)
{
// 这种情况的崩溃信息,就另某他法来捕获吧
NSArray *callStack = [CrashHandler backtrace];
NSLog(@"信号捕获崩溃,堆栈信息:%@",callStack);
CrashHandler *crashObject = [CrashHandler sharedInstance];
NSException *customException = [NSException exceptionWithName:kSignalExceptionName
reason:[NSString stringWithFormat:NSLocalizedString(@"Signal %d was raised.", nil),signal]
userInfo:@{kSignalKey:[NSNumber numberWithInt:signal]}];
[crashObject performSelectorOnMainThread:@selector(handleException:) withObject:customException waitUntilDone:YES];
}
原文地址:https://www.cnblogs.com/zoule/p/15234499.html
- 【关关的刷题日记62】Leetcode 104. Maximum Depth of Binary Tree
- DataAnnotations - InverseProperty Attribute:
- 【关关的刷题日记63】Leetcode 111 Minimum Depth of Binary Tree
- Configure Many-to-Many relationship:
- 【关关的刷题日记64】Leetcode 110 Balanced Binary Tree
- 左手用R右手Python系列之——json序列化与反序列化
- 【干货】GAN调研:多极扩展(跨域和条件的GAN扩展模型调研)
- 【干货】TensorFlow实战——图像分类神经网络模型
- HTML5手机APP开发入(5)
- 这种自带黑科技的R包,请给我来一打
- 4927 线段树练习5
- codevs4919 线段树练习4
- 利用OpenCV和深度学习实现人脸检测
- 洛谷P2676 超级书架
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- Ubuntu14.04安装、配置与卸载QT5的步骤详解
- CentOS 8 安装 MariaDB的详细教程
- Android中RecyclerView拖拽、侧删功能的实现代码
- Android单个RecyclerView实现列表嵌套的效果
- Android如何禁止向EditText控件中输入内容详解
- 小程序视角下同构方案思考
- Android基于自带的DownloadManager实现下载功能示例
- Linux服务器搭建nvidia-docker环境过程详解
- Android开发中libs和jinLibs文件夹的作用详解
- Android多线程之同步锁的使用
- android.graphics.Matrix类用法分析
- 使用VSCode和SSH进行远程开发
- Android利用CountDownTimer实现倒计时功能 Android实现停留5s跳转到登录页面
- Android开发之对话框案例详解(五种对话框)
- Linux下一只五颜六色的「猫」