RunLoop总结:RunLoop的应用场景(五)
今天要介绍的RunLoop应用场景感觉很酷炫,我们可能不常用到,但是对于做Crash 收集的 SDK可能会用得比较频繁吧。相比关于RunLoop 可以让应用起死回生,大家都听说过,可是怎么实现呢?今天我就来实际试验一下。
资料
- sunnyxx线下分享RunLoop (这是一份关于线下分享与讨论RunLoop的视频,备用地址:https://pan.baidu.com/s/1pLm4Vf9)
- 漫谈iOS Crash收集框架(简单介绍了下iOS 中Crash 的一些知识。)
- IOS程序异常crash捕获与拦截 (我下面的Demo 就是在这部分代码上做了简化,以方便理解)
原理
iOS应用崩溃,常见的崩溃信息有EXC_BAD_ACCESS
、SIGABRT XXXXXXX
,而这里分为两种情况,一种是未被捕获的异常,我们只需要添加一个回调函数,并在应用启动时调用一个 API即可;另一种是直接发送的 SIGABRT XXXXXXX
,这里我们也需要监听各种信号,然后添加回调函数。
针对情况一,其实我们都见过。我们在收集App崩溃信息时,需要添加一个函数 NSSetUncaughtExceptionHandler(&HandleException)
,参数 是一个回调函数,在回调函数里获取到异常的原因,当前的堆栈信息等保存到 dump文件,然后供下次打开App时上传到服务器。
其实,我们在HandleException回调函数中,可以获取到当前的RunLoop,然后获取该RunLoop中的所有Mode,手动运行一遍。
针对情况二,首先针对多种要捕获的信号,设置好回调函数,然后也是在回调函数中获取RunLoop,然后拿到所有的Mode,手动运行一遍。
代码实现
第一步,我创建了一个处理类,并添加一个单例方法。(代码见末尾的Demo)
第二步,在单例中对象实例化时,添加 异常捕获 和 signal 处理的 回调函数。
- (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);
}
第三步,分别实现 异常捕获的回调 和 signal 的回调。
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];
}
第四步,添加让应用起死回生的 RunLoop 代码
- (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];
}
}
因为我这里弄了一个AlertView弹窗,所以必须要回到主线程来处理。
实际上,RunLoop 相关的代码:
CFRunLoopRef runLoop = CFRunLoopGetCurrent();
CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);
while (!ignore) {
for (NSString *mode in (__bridge NSArray *)allModes) {
CFRunLoopRunInMode((CFStringRef)mode, 0.001, false);
}
}
CFRelease(allModes);
完全可以写在 上面的 HandleException 回调 和 SignalHandler回调中。
第五步,写一段会导致崩溃的代码
我是在ViewController 中添加了一个点击事件,弄了一个数组越界的Bug:
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
NSArray *array =[NSArray array];
NSLog(@"%@",[array objectAtIndex:1]);
}
动态效果图:
sunnyxx 称之为回光返照,为什么呢?
我再一次点击视图,应用依然还是崩溃了,只能防止第一次崩溃。
我测试了,确实是第二次应用崩溃,未能起死回生。
文中的示例代码都来自:RunLoopDemos中的RunLoopDemo04
RunLoop总结:RunLoop的应用场景(五)的更多相关文章
- 何为RunLoop?RunLoop有哪些应用场景?
一.RunLoop的作用 一个应用开始运行以后放在那里,如果不对它进行任何操作,这个应用就像静止了一样,不会自发的有任何动作发生,但是如果我们点击界面上的一个按钮,这个时候就会有对应的按钮响应事件发生 ...
- {Python之线程} 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Threading模块 九 锁 十 信号量 十一 事件Event 十二 条件Condition(了解) 十三 定时器
Python之线程 线程 本节目录 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Thr ...
- RunLoop 总结:RunLoop的应用场景(一)
参考资料 好的书籍都是值得反复看的,那好的文章,好的资料也值得我们反复看.我们在不同的阶段来相同的文章或资料或书籍都能有不同的收获,那它就是好文章,好书籍,好资料.关于iOS 中的RunLoop资料非 ...
- RunLoop 总结:RunLoop的应用场景(二)
上一篇讲了使用RunLoop保证子线程的长时间存活,而不是执行完任务后就立刻销毁的应用场景.这一篇就讲述一下RunLoop如何保证NSTimer在视图滑动时,依然能正常运转. 参考资料 好的书籍都是值 ...
- iOS开发 - 啰嗦讲解 Runloop
写在前面的 为什么要了解 RunLoop?如果你想成为一个高级iOS开发工程师,那这是你必须了解的东西,他能帮助你更好的理解底层实现的原理,可以利用它的特性做出一些高效又神奇的功能.RunLoop这个 ...
- 都在说RunLoop...... 到底什么是RunLoop?
RunLoop(消息循环):说白了就是一种事件监听循环.就好比是一个while循环,监听到事件就起来,没有就休息. 介绍: 它可以在不同模式下进行切换,iOS有五种模式,其中UIInitializat ...
- Runloop的再学习之浅析(一)
一,认识RunLoop 我的理解: 1. 在编程的世界里,万物皆对象.所以RunLoop 实际上也是一个对象,这个对象管理了其需要 处理的事件和消息,并提供了一个入口函数来执行上面 Event Loo ...
- iOS Runloop 消息循环
介绍 Runloop是一种事件监听循环,可以理解成一个while死循环,监听到事件就起来,没有就休息. Runloop可以在不同模式下进行切换,iOS有五种模式,其中UIInitializationR ...
- iOS开发——高级篇——Runloop相关一
一.什么是runLoop 1.说白了,runloop就是运行循环 2.runloop,他是多线程的法宝 通常来讲,一个线程一次只能执行一个任务,执行完之后就退出线程.但是,对于主线程是不能退出的,因此 ...
- 聊聊Runloop
1.什么是Runloop 在开始聊RunLoop之前,我们先来了解一下程序的执行原理.一般来说,程序是在线程中执行,一个线程一次只能执行一个任务(关于GCD,可看上篇文章介绍),执行完成后线程就会退出 ...
随机推荐
- javascript 作用域链与执行环境
前言:这是笔者学习之后自己的理解与整理.如果有错误或者疑问的地方,请大家指正,我会持续更新! 作用域.作用域链.执行环境.执行环境栈以及this的概念在javascript中非常重要,本人经常弄混淆, ...
- JQuery开发报错集锦
报错一:JQuery $.each遍历JSON字符串报Uncaught TypeError:Cannot use 'in' operator to search for "70". ...
- Android基础字符串String.md
问题抛出 String这个常量在我们代码中会经常被用到,那么我们了解 String stringbuffer StringBudilder三者之间的区别吗 问题解答 String 字符串常量,位于常量 ...
- java工厂设计模式初步
没有利用反射机制定义的简单工厂类 interface Fruit{ public void eat(); } class Apple implements Fruit{ public void eat ...
- .NET Core2.0+MVC 用session,cookie实现的sso单点登录
博主刚接触.NET Core2.0,想做一个单点登录的demo,所以参考了一些资料,这里给上链接: 1.http://www.cnblogs.com/baibaomen/p/sso-sequence- ...
- [HNOI 2002]跳蚤
Description Z城市居住着很多只跳蚤.在Z城市周六生活频道有一个娱乐节目.一只跳蚤将被请上一个高空钢丝的正中央.钢丝很长,可以看作是无限长.节目主持人会给该跳蚤发一张卡片.卡片上写有N+1个 ...
- [HNOI 2004]敲砖块
Description 在一个凹槽中放置了 n 层砖块.最上面的一层有n 块砖,从上到下每层依次减少一块砖.每块砖都有一个分值,敲掉这块砖就能得到相应的分值,如下图所示. 14 15 4 3 23 3 ...
- [SDOI2009]虔诚的墓主人
题目描述 小W是一片新造公墓的管理人.公墓可以看成一块N×M的矩形,矩形的每个格点,要么种着一棵常青树,要么是一块还没有归属的墓地. 当地的居民都是非常虔诚的基督徒,他们愿意提前为自己找一块合适墓地. ...
- 计蒜客NOIP模拟赛(2) D1T2 表演艺术
凡和邻家男孩玩完了纸牌,兴致很高,于是准备了一场表演艺术对抗赛. 他特意请来了很多表演艺术家,分成绿黑两队,进行名为 PK,实则捞金的表演. 凡为了捞金,开设了一个赌局,在比赛开始之前招揽人们来押注谁 ...
- 【Codeforces Round #430 (Div. 2) A C D三个题】
·不论难度,A,C,D自己都有收获! [A. Kirill And The Game] ·全是英文题,述大意: 给出两组区间端点:l,r,x,y和一个k.(都是正整数,保证区间不为空),询问是否 ...