什么是言语反常呢?简单来说便是因为不标准编写代码造成的问题称之为言语反常。

比方数组越界、调用某个类未实现的办法等等。那么怎么经过看溃散陈述来确认溃散是否由言语反常导致的呢?首要要看的便是 Exception information 这一栏是否遵从下面的范式:

Exception Type:  EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Triggered by Thread:  0

还有便是,当溃散是因为未捕获的言语反常导致的时候,溃散陈述中肯定会包括 Last Exception Backtrace 这一栏信息:

iOS crash 报告分析系列 - 语言异常崩溃

下面,咱们经过详细剖析Last Exception Backtrace 这一栏信息,来去定位是什么原因导致的溃散。

Last Exception Backtrace 剖析

在这一栏,操作体系通常会记录关于当前溃散的完好函数调用栈。该栏的回溯会以明确抛出言语反常的帧结尾。

在函数回溯的进程中,你会发现有关抛出反常的办法的要害信息,以及代码的哪个部分调用了引发反常的办法。比方下面的比如:

溃散代码:
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
  NSArray *arr = @[];
  NSLog(@"%d", arr[5]);
}
Last Exception Backtrace:
0   CoreFoundation                	       0x191560e38 __exceptionPreprocess + 164
1   libobjc.A.dylib               	       0x18a6f78d8 objc_exception_throw + 60
2   CoreFoundation                	       0x191672b48 __CFArrayHash + 0
3   CrashDemo                     	       0x1027d5e18 -[ViewController touchesBegan:withEvent:] + 116
4   UIKitCore                     	       0x19392ddfc forwardTouchMethod + 284
5   UIKitCore                     	       0x1938281b0 -[UIWindow _sendTouchesForEvent:] + 356
6   UIKitCore                     	       0x193827770 -[UIWindow sendEvent:] + 3284
7   UIKitCore                     	       0x193826a20 -[UIApplication sendEvent:] + 676
8   UIKitCore                     	       0x1938260d8 __dispatchPreprocessedEventFromEventQueue + 7084
9   UIKitCore                     	       0x19386de00 __processEventQueue + 5632
10  UIKitCore                     	       0x1944cb820 updateCycleEntry + 168
11  UIKitCore                     	       0x193d7e5b0 _UIUpdateSequenceRun + 84
12  UIKitCore                     	       0x1943cd310 schedulerStepScheduledMainSection + 172
13  UIKitCore                     	       0x1943cc4dc runloopSourceCallback + 92
14  CoreFoundation                	       0x19162cf24 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
15  CoreFoundation                	       0x1916392fc __CFRunLoopDoSource0 + 176
16  CoreFoundation                	       0x1915bd1c0 __CFRunLoopDoSources0 + 244
17  CoreFoundation                	       0x1915d2b7c __CFRunLoopRun + 836
18  CoreFoundation                	       0x1915d7eb0 CFRunLoopRunSpecific + 612
19  GraphicsServices              	       0x1cb7cd368 GSEventRunModal + 164
20  UIKitCore                     	       0x193acd668 -[UIApplication _run] + 888
21  UIKitCore                     	       0x193acd2cc UIApplicationMain + 340
22  CrashDemo                     	       0x1027d60b8 main + 120
23  dyld                          	       0x1afed0960 start + 2528

陈述解读: 首要,第 0 – 1 帧能够看出是操作体系抛出了反常。第 2 帧能够剖析出当前反常是与 NSArray 有关的。第 3 帧能够看出是 ViewControllertouchesBegan:withEvent: 调用导致了该溃散的发生。定位到这,咱们就能够去相应的代码那,去具体剖析到底是数组的什么操作导致了该溃散的发生。

第 4 – 23 帧则是 app 发动和事情转发的进程,跟溃散原因查询关系不大。

Tips:假如 API 抛出 doesNotRecognizeSelector(_:) 的反常,那么这个反常可能是因为僵尸对象造成的。怎么剖析能够看这儿。

查看反常信息

操作体系供给的未捕获反常处理程序在停止进程之前,会将反常消息记录到操控台。所以,假如你能复现,你会在操控台看到如下的打印:

***** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArray0 objectAtIndex:]: index 5 beyond bounds for empty NSArray'**

这个信息就能够很明显的看出是因为数组越界而导致的溃散了。

那为什么溃散陈述不包括这么简单明了的日志呢?下面是 Apple 的回答: iOS、iPadOS、watchOS 和 tvOS 溃散陈述不包括反常消息,以避免经过反常消息走漏有关用户的私家信息。

剖析体系言语反常引起的溃散

在确认是操作体系的 API 抛出反常后,咱们应该查阅该 API 的文档来确认触发反常的条件。还测验运用 Xcode 调试器去重现溃散,以在操控台中获取有关反常的其他信息。最终,能够运用回溯中的帧作为需要测验的特定代码的方向。

假如无法重现溃散的话,就需要运用一切的线程回溯(不仅仅是反常回溯)作为头绪,去剖析当溃散发生时,程序到底在做什么。