1.前言
前几天我们项目闪退之后遇到的一个Crash,之后逛了许多论坛,博客都没有找到满意的回复
在自己做了深入的研究之后,对iOS的看门狗机制有了一个基本的了解
而有很多奇怪的Crash可能恰恰就是因为iOS的看门狗机制导致的
今天分享出来,希望能帮助到后来者,下面我们先来看看Crash Report
2. iOS App Crash Report 分析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
Date/Time: 2016-01-25 12:19:48.746 +0100 Launch Time: 2016-01-22 15:12:37.422 +0100 OS Version: iOS 8.4 (12H143) Report Version: 105 Exception Type: 00000020 Exception Codes: 0x000000008badf00d Highlighted Thread: 0 Application Specific Information: <BKNewProcess: 0x12cd26cf0; com.scasy.Dinnn; pid: 248; hostpid: -1> has active assertions beyond permitted time: {( <BKProcessAssertion: 0x12ce1b400> id: 248-C89C6FAD-B496-46ED-B59A-20D976A02D10 name: Called by ExternalAccessory, from <redacted> process: <BKNewProcess: 0x12cd26cf0; com.scasy.Dinnn; pid: 248; hostpid: -1> permittedBackgroundDuration: 180.000000 reason: finishTask owner pid:248 preventSuspend preventIdleSleep preventSuspendOnSleep )} Elapsed total CPU time (seconds): 0.130 (user 0.130, system 0.000), 1% CPU Elapsed application CPU time (seconds): 0.044, 0% CPU Thread 0 name: Dispatch queue: com.apple.main-thread Thread 0: 0 libsystem_kernel.dylib 0x342ec474 mach_msg_trap + 20 1 libsystem_kernel.dylib 0x342ec269 mach_msg + 37 2 CoreFoundation 0x25a1256f __CFRunLoopServiceMachPort + 143 3 CoreFoundation 0x25a10b15 __CFRunLoopRun + 1013 4 CoreFoundation 0x2595d1fd CFRunLoopRunSpecific + 473 5 CoreFoundation 0x2595d00f CFRunLoopRunInMode + 103 6 Foundation 0x266c7139 -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 261 7 Foundation 0x26715221 -[NSRunLoop(NSRunLoop) run] + 77 8 Dinnn 0x0014af59 -[ConnectServerViewController updateInitDinnnThread:] (ConnectServerViewController.m:425) 9 Foundation 0x2678c5cb __NSThreadPerformPerform + 383 10 CoreFoundation 0x25a12fad __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 13 11 CoreFoundation 0x25a123bb __CFRunLoopDoSources0 + 215 12 CoreFoundation 0x25a10a21 __CFRunLoopRun + 769 13 CoreFoundation 0x2595d1fd CFRunLoopRunSpecific + 473 14 CoreFoundation 0x2595d00f CFRunLoopRunInMode + 103 15 GraphicsServices 0x2d2d81fd GSEventRunModal + 133 16 UIKit 0x29129a05 UIApplicationMain + 1437 17 Dinnn 0x00088c47 main (main.m:17) 18 libdyld.dylib 0x34235aad start + 1 |
我们先定位异常类型: Exception Type: 00000020
简而言之,Exception Type: 00000020 意味着你正在做的异步网络在主线程,当连接或运行缓慢,应用程序可以终止iOS。这将随机发生。
最常见的原因是在一个网络中的应用程序的看门狗超时崩溃是同步网络的主要线程。
这里有三个因素:
1.同步网络-这是您的网络请求和阻止等待响应的地方。
2.主线程-同步网络一般不理想,但它会导致特定问题,如果你在主线程上做的话。请记住,主线程负责运行用户界面。如果你阻塞主线程的任何显着的时间,用户界面变得很迟钝。
3.长期超时-如果网络消失了(例如,用户是在火车进入隧道),任何挂起的网络请求不会失败直到超时过期了。大多数网络超时是以分钟计算,即阻塞同步网络请求在主线程可以同时保持用户界面的响应时间。
试图通过减少网络超时来避免这个问题是一个不好的想法。在某些情况下,它可以采取许多秒的网络请求成功,如果你总是提前时间,那么你永远不会取得任何进展。
看门狗-为了保持用户界面的响应,iOS系统包括一个看门狗机制。如果您的应用程序未能响应某些用户界面事件(启动、暂停、恢复、终止)的时间,该看门狗将杀死您的应用程序,并产生一个看门狗超时崩溃报告。
这个问题的一个棘手的方面是,它高度依赖于网络环境。如果你总是在你的办公室里测试你的应用,在你的网络连接是好的,你永远不会看到这种类型的崩溃。然而,一旦你开始部署你的应用程序,最终用户谁会运行在各种网络环境崩溃,像这样。
总结,如果您在主线程上进行同步联网呼叫,您的应用程序将受到看门狗超时崩溃,当它部署到一个广泛的环境。
从上面的Crash report中的
6,7,行我们能看到具体原因, 8 行 我们可以看到具体位置。
具体:
关于-(BOOL)runMode:(NSString *)mode beforeDate:(NSDate *)date;方法
指定runloop模式来处理输入源,首个输入源或date结束退出。
暂停当前处理的流程,转而处理其他输入源,当date设置为[NSDate distantFuture](将来,基本不会到达的时间),所以除非处理其他输入源结束,否则永不退出处理暂停的当前处理的流程。
报告里很明显告诉我们这里被堵塞了,说明这个Run loop当前是在主线程上,所以最后我们的APP被iOS的看门狗机制杀死了。
终:
一旦你确认这个问题与你的网络代码相关,有一个共同的解决方案:
异步网络-这个问题的最佳解决方案是异步运行您的网络代码。异步网络代码有很多优点,至少是它可以让你安全地访问网络,而不必担心线程。
在辅助线程同步网络如果它运行你的网络代码异步的比登天还难(也许你有一个大的便携式的代码库,假定同步组网工作),你可以通过在辅助线程上运行你的同步码避免看门狗。
如何异步运行网络代码,包括多线程这个你可以查看Apple文档相关资料