什么是言语反常呢?简单来说便是因为不标准编写代码造成的问题称之为言语反常。
比方数组越界、调用某个类未实现的办法等等。那么怎么经过看溃散陈述来确认溃散是否由言语反常导致的呢?首要要看的便是 Exception information 这一栏是否遵从下面的范式:
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Triggered by Thread: 0
还有便是,当溃散是因为未捕获的言语反常导致的时候,溃散陈述中肯定会包括 Last Exception Backtrace
这一栏信息:
下面,咱们经过详细剖析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 帧能够看出是 ViewController
的 touchesBegan: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 调试器去重现溃散,以在操控台中获取有关反常的其他信息。最终,能够运用回溯中的帧作为需要测验的特定代码的方向。
假如无法重现溃散的话,就需要运用一切的线程回溯(不仅仅是反常回溯)作为头绪,去剖析当溃散发生时,程序到底在做什么。