Crash 崩溃日志

Debug 崩溃

通常产生的崩溃类型为两种:SIGABRT(也称为 EXC_CRASH)和 EXC_BAD_ACCESS(这种也会显示为 SIGBUS 或 SIGSEGV)。

SIGABRT 是最好处理的一个崩溃,因为它可控。

EXC_BAD_ACCESS,换句话说,很难 debug,因为它只发生于 app 运行在一个糟糕的状态下,通常是内存问题导致的。

当 app 崩溃的时候,Xcode 会停在当前的崩溃的线程。通常都是 Thread 1,也就是 app 的主线程,如果你的代码使用了队列或后台线程,app 就可能崩溃在其他线程。

从上图可知,当前 Xcode 高亮在 main() 函数。然而这不能提供多少信息,我们不得不更深度的挖掘。

为了看到更多的回调栈,把 debug 导航栏下面拖到最右边。

上面的每一条都列出了调用子 app 的函数或方法。最底下的函数是 start(),最先调用的就是它。然后再调用里面的 main() 函数,这是程序开始的地方,所以总是在最下面。main() 函数会再调用一个叫 UIApplicationMain() 的方法。然后 UIApplicationMain() 里面会调用 UIApplication 对象的 _run 方法,这个又会调用 CFRunLoopRunInMode(),接着是 CFRunLoopRunSpecific(),然后依次这样,一直到 __pthread_kill

所有这些函数和方法,除了 main(),其他都会变灰色。因为它们都来自与内建的 iOS 框架。所以没有相对应的源码。

在栈跟踪里唯一有源码的是 main.m,所以这就是为什么 Xcode 会在崩溃时停在这个地方的原因。通常这容易混淆新手。

异常断点

那么该怎样找到 app 崩溃的那行代码呢?唔,只要你在栈跟踪里看到 app 抛出了一个 exception。(调用栈其中一个异常就叫做 objc_excption_rethrow.)

当程序捕获到正在进行某件不该发生的事情时就会抛出异常。此时你看到的只是异常产生的结果:app 出错了,异常被抛出,并且 Xcode 告诉了你结果。理想情况是,你不会想直接看到异常被抛出。

幸好,你可以使用异常断点来告诉 Xcode 在即将抛出异常的刹那间暂停程序。

内存错误

让我们来看看内存错误的异常。当出现 EXC_BAD_ACCESS 错误的时候意味着发生了内存问题。

当发生内存问题的时候通常很难定位错误,如果你看到 Xcode 发出了警告,通常这里就会有某些问题。这个例子里,Xcode 已经提示出了问题所在和解决方法。

再看另一个例子

在这个例子中,异常断点停在了 main() 函数而没有高亮某行代码,说明这时候崩溃还没有发生在 app 里的代码中。这些方法都不属于 app,除了 main()

如果你从上往下看看栈的调用,你会发现这些方法与 NSObject 和 Key-Value Coding 有关。下面调用了 [UIRuntimeOutletConnection connect]。我不知道那是什么,但似乎做了些连接 outlets 的一些事情。再往下看就是从 nib 加载视图的一些方法。这些倒是给了你一些线索。

然而 Xcode 的 Debug 面板没有任何直接的错误信息。这是因为异常还没有抛出。异常断点在它要告诉你错误原因之前暂停了程序。有时开启异常断点只能得到部分错误信息,你想要的却没有。

为了查看全部的错误信息,点击继续执行程序。

你可能需要点几次,然后才能得到错误信息:

Problems[14961:f803] *** Terminating app due to uncaught exception 'NSUnknownKeyException',  
reason: '[<MainViewController 0x6b3f590> setValue:forUndefinedKey:]: this class is not  
key value coding-compliant for the key button.'  
*** First throw call stack:
(0x13ba052 0x154bd0a 0x13b9f11 0x9b1032 0x922f7b 0x922eeb 0x93dd60 0x23091a 0x13bbe1a 
0x1325821 0x22f46e 0xd6e2c 0xd73a9 0xd75cb 0xd6c1c 0xfd56d 0xe7d47 0xfe441 0xfe45d  
0xfe4f9 0x3ed65 0x3edac 0xfbe6 0x108a6 0x1f743 0x201f8 0x13aa9 0x12a4fa9 0x138e1c5  
0x12f3022 0x12f190a 0x12f0db4 0x12f0ccb 0x102a7 0x11a9b 0x2872 0x27e5)  
terminate called throwing an exception  

首先忽略下面的数字。它们只是调用栈的信息。

让人感兴趣的是这些:

  • NSUnknownKeyException
  • MainViewController
  • “this class is not key value coding-compliant for the key button”

异常的名称,NSUnknownKeyException,通常能够告诉我们错误的类型。这里它说的是在某些地方有个 "unknown key"。这里的某些地方指的是 MainViewController,并且 key 的名字是 "button"。

我们之前已经知道了错误发生在加载 nib 时。

崩溃日志

// 1: Process Information
Incident Identifier: 8369CDE7-A415-4A8B-978D-109839CB1A92  
CrashReporter Key:   0c7df4de2031e0f2e104051cd820812771c7d956  
Hardware Model:      iPhone5,3  
Process:             zhxy_soha_HD [924]  
Path:                /private/var/mobile/Containers/Bundle/Application/E42720D7-1CA1-42F8-853B-97B298A648C2/zhxy_soha_HD.app/zhxy_soha_HD  
Identifier:          vn.sohagame.sg40  
Version:             ??? (???)  
Code Type:           ARM (Native)  
Parent Process:      launchd.development [1]

// 2: Basic Information
Date/Time:           2015-01-21 06:43:52.675 -0800  
Launch Time:         2015-01-21 06:43:50.355 -0800  
OS Version:          iOS 8.1 (12B411)  
UDID:                31f5a13222665fd3b221114ae00bf4d16722553b  
Report Version:      105

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

// 4: Threads backtraces
Thread 0 name:  Dispatch queue: com.apple.main-thread  
Thread 0:  
0   libsystem_kernel.dylib            0x3943f19c 0x3942a000 + 86428  
1   libsystem_c.dylib                 0x3939ea6c 0x39394000 + 43628  
2   libsystem_c.dylib                 0x3939e9bc 0x39394000 + 43452  
3   QuartzCore                        0x2e526e4e 0x2e411000 + 1138254  
4   GLEngine                          0x2df0e44e 0x2de3b000 + 865358  
5   IMGSGX543RC2GLDriver              0x29ebed80 0x29eae000 + 68992  
6   IMGSGX543RC2GLDriver              0x29eb444c 0x29eae000 + 25676  
7   IMGSGX543RC2GLDriver              0x29eba0b4 0x29eae000 + 49332  
8   IMGSGX543RC2GLDriver              0x29eb1d96 0x29eae000 + 15766  
9   GLEngine                          0x2df0e386 0x2de3b000 + 865158  
10  GLEngine                          0x2df0e2b6 0x2de3b000 + 864950  
11  OpenGLES                          0x2df19062 0x2df13000 + 24674  
12  zhxy_soha_HD                      0x009a7594 0x45000 + 9840020  
13  zhxy_soha_HD                      0x0098cd28 0x45000 + 9731368  
14  zhxy_soha_HD                      0x0098da54 0x45000 + 9734740  
15  QuartzCore                        0x2e46b7fe 0x2e411000 + 370686  
16  QuartzCore                        0x2e46b666 0x2e411000 + 370278  
17  IOMobileFramebuffer               0x32e29828 0x32e24000 + 22568  
18  IOKit                             0x2c45d4de 0x2c459000 + 17630  
19  CoreFoundation                    0x2b4ee6c2 0x2b433000 + 767682  
20  CoreFoundation                    0x2b4feb90 0x2b433000 + 834448  
21  CoreFoundation                    0x2b4feb2a 0x2b433000 + 834346  
22  CoreFoundation                    0x2b4fd12c 0x2b433000 + 827692  
23  CoreFoundation                    0x2b44b20c 0x2b433000 + 98828  
24  CoreFoundation                    0x2b44b01e 0x2b433000 + 98334  
25  GraphicsServices                  0x3291d0a4 0x32914000 + 37028  
26  UIKit                             0x2ea571cc 0x2e9e9000 + 451020  
27  zhxy_soha_HD                      0x00061c20 0x45000 + 117792  
28  zhxy_soha_HD                      0x00049484 0x45000 + 17540

Thread 1 name:  Dispatch queue: com.apple.libdispatch-manager  
Thread 1:  
0   libsystem_kernel.dylib            0x3942b2a0 0x3942a000 + 4768  
1   libdispatch.dylib                 0x393649fc 0x39357000 + 55804  
2   libdispatch.dylib                 0x3935a20e 0x39357000 + 12814

Thread 2:  
0   libsystem_kernel.dylib            0x3943f9cc 0x3942a000 + 88524  
1   libsystem_pthread.dylib           0x394b9ea8 0x394b9000 + 3752  
2   libsystem_pthread.dylib           0x394b9b80 0x394b9000 + 2944

Thread 3:  
0   libsystem_kernel.dylib            0x3943f9cc 0x3942a000 + 88524  
1   libsystem_pthread.dylib           0x394b9ea8 0x394b9000 + 3752  
2   libsystem_pthread.dylib           0x394b9b80 0x394b9000 + 2944

Thread 4:  
0   libsystem_kernel.dylib            0x3943f9cc 0x3942a000 + 88524  
1   libsystem_pthread.dylib           0x394b9ea8 0x394b9000 + 3752  
2   libsystem_pthread.dylib           0x394b9b80 0x394b9000 + 2944

Thread 5:  
0   libsystem_kernel.dylib            0x3943f9cc 0x3942a000 + 88524  
1   libsystem_pthread.dylib           0x394b9ea8 0x394b9000 + 3752  
2   libsystem_pthread.dylib           0x394b9b80 0x394b9000 + 2944

Thread 6 name:  Dispatch queue: NSOperationQueue 0x15584d50 :: NSOperation 0x156824f0  
Thread 6 Crashed:  
0   libsystem_kernel.dylib            0x3943edfc 0x3942a000 + 85500  
1   libsystem_pthread.dylib           0x394bcd32 0x394b9000 + 15666  
2   libsystem_c.dylib                 0x393de904 0x39394000 + 305412  
3   libc++abi.dylib                   0x3871c9c4 0x3871c000 + 2500  
4   libc++abi.dylib                   0x3873666c 0x3871c000 + 108140  
5   libobjc.A.dylib                   0x38df8f22 0x38df2000 + 28450  
6   libc++abi.dylib                   0x38733de0 0x3871c000 + 97760  
7   libc++abi.dylib                   0x387335a4 0x3871c000 + 95652  
8   libobjc.A.dylib                   0x38df8d5a 0x38df2000 + 27994  
9   CoreFoundation                    0x2b44d834 0x2b433000 + 108596  
10  zhxy_soha_HD                      0x00aaea48 0x45000 + 10918472  
...
...

Thread 7 name:  AFNetworking  
Thread 7:  
0   libsystem_kernel.dylib            0x3942b4f0 0x3942a000 + 5360  
1   libsystem_kernel.dylib            0x3942b2e4 0x3942a000 + 4836  
2   CoreFoundation                    0x2b4fe936 0x2b433000 + 833846  
3   CoreFoundation                    0x2b4fcedc 0x2b433000 + 827100  
4   CoreFoundation                    0x2b44b20c 0x2b433000 + 98828  
5   CoreFoundation                    0x2b44b01e 0x2b433000 + 98334  
6   Foundation                        0x2c182bf8 0x2c177000 + 48120  
7   Foundation                        0x2c1d10b8 0x2c177000 + 368824  
8   zhxy_soha_HD                      0x00a01632 0x45000 + 10208818  
...
...

Thread 8 name:  com.apple.NSURLConnectionLoader  
Thread 8:  
0   libsystem_kernel.dylib            0x3942b4f0 0x3942a000 + 5360  
1   libsystem_kernel.dylib            0x3942b2e4 0x3942a000 + 4836  
...
...

Thread 9 name:  com.apple.CFSocket.private  
Thread 9:  
0   libsystem_kernel.dylib            0x3943f08c 0x3942a000 + 86156  
1   CoreFoundation                    0x2b503102 0x2b433000 + 852226  
2   libsystem_pthread.dylib           0x394bbe90 0x394b9000 + 11920  
3   libsystem_pthread.dylib           0x394bbe02 0x394b9000 + 11778  
4   libsystem_pthread.dylib           0x394b9b8c 0x394b9000 + 2956

// 5: Thread state
Thread 6 crashed with ARM Thread State (32-bit):  
    r0: 0x00000000    r1: 0x00000000      r2: 0x00000000      r3: 0x393d1095
    r4: 0x00000006    r5: 0x03bc8000      r6: 0x3bafa840      r7: 0x03bc6dc8
    r8: 0x1559cc90    r9: 0x00000000     r10: 0x15ad6e00     r11: 0x1559ccb4
    ip: 0x00000148    sp: 0x03bc6dbc      lr: 0x394bcd37      pc: 0x3943edfc
  cpsr: 0x00000010

// 6: Binary images
Binary Images:  
0x45000 - 0xc50fff zhxy_soha_HD armv7  <bc1c594b4ecf362082a4e8d435f5c3ec> /var/mobile/Containers/Bundle/Application/E42720D7-1CA1-42F8-853B-97B298A648C2/zhxy_soha_HD.app/zhxy_soha_HD  
0x1fe43000 - 0x1fe66fff dyld armv7s  <b01d37db5b0d3a2ea1ccf17afc40a896> /usr/lib/dyld  
0x29eae000 - 0x29fc3fff IMGSGX543RC2GLDriver armv7s  <77af51df8599375fada078a15b6e8bed> /System/Library/Extensions/IMGSGX543RC2GLDriver.bundle/IMGSGX543RC2GLDriver  
0x29fcf000 - 0x2a13bfff AVFoundation armv7s  <20cb3fb302c83ede8cc708d8dea2b480> /System/Library/Frameworks/AVFoundation.framework/AVFoundation  
0x2a13c000 - 0x2a19afff libAVFAudio.dylib armv7s  <07753e16a2e136e2bbe7937c1d2833f6> /System/Library/Frameworks/AVFoundation.framework/libAVFAudio.dylib  
0x2a1d4000 - 0x2a1d4fff Accelerate armv7s  <3c10ee15d8363fa58b719f2abca91b06> /System/Library/Frameworks/Accelerate.framework/Accelerate  
0x2a1e5000 - 0x2a400fff vImage armv7s  <3358de09601333a2881365e5c74c681e> /System/Library/Frameworks/Accelerate.framework/Frameworks/vImage.framework/vImage  
0x2a401000 - 0x2a4e7fff libBLAS.dylib armv7s  <b46b7fd3985f371ca26b10f268965e63> /System/Library/Frameworks/Accelerate.framework/Frameworks/vecLib.framework/libBLAS.dylib  
0x2a4e8000 - 0x2a7acfff libLAPACK.dylib armv7s  <eb228c255d9e349391cd6b227a9d2744> /System/Library/Frameworks/Accelerate.framework/Frameworks/vecLib.framework/libLAPACK.dylib  
0x2a7ad000 - 0x2a7befff libLinearAlgebra.dylib armv7s  <d2e989bc1bad320b918c37d3642db4b6> /System/Library/Frameworks/Accelerate.framework/Frameworks/vecLib.framework/libLinearAlgebra.dylib  
0x2a7bf000 - 0x2a83bfff libvDSP.dylib armv7s  <07cf0625bd813336920eb5b62f99be06> /System/Library/Frameworks/Accelerate.framework/Frameworks/vecLib.framework/libvDSP.dylib  
0x2a83c000 - 0x2a84efff libvMisc.dylib armv7s  <07997e6e46fa35a18c6ddacf62f326d8> /System/Library/Frameworks/Accelerate.framework/Frameworks/vecLib.framework/libvMisc.dylib  
0x2a84f000 - 0x2a84ffff vecLib armv7s  <108b763f155130828fa123813e3ff5f5> /System/Library/Frameworks/Accelerate.framework/Frameworks/vecLib.framework/vecLib  
0x2a850000 - 0x2a876fff Accounts armv7s  <7540bbbab44638cbbfc6f8e660b882e5> /System/Library/Frameworks/Accounts.framework/Accounts  
0x2a877000 - 0x2a877fff AdSupport armv7s  <7d5801dc36bd37fd85c94196efd32155> /System/Library/Frameworks/AdSupport.framework/AdSupport  
0x2a878000 - 0x2a8e8fff AddressBook armv7s  <f14b87a5995235f7b4758b9177eacfff> /System/Library/Frameworks/AddressBook.framework/AddressBook  
...
...

让我们分部份来看看:

(1)Process Information
第一部分告诉了你一些有关崩溃的信息

  • Incident Identifier 表示每个崩溃报告的唯一标识。
  • CrashReporter key 同样也是一个唯一 key,它是设备标识符的映射。即使是匿名的,但它仍然能告诉你一个非常有用的信息:如果你看到 100 个崩溃日志有着同样的这个 key,它意味着这个问题可能不是广泛的问题,也就是说只是个别设备上才发生的崩溃。
  • Hardware Model 标识符表示设备的类型。
  • Process 是应用的名称。括号中的数字表示崩溃时的进程 ID。
  • 其他的应该一看就明白了。

(2)Basic Information
这部分告诉了你崩溃发生的时间,还有设备运行的 iOS 系统版本。如果你有一堆 iOS 6.0 崩溃的日志,那说明你的问题很可能就是跟 iOS 6 有关。

(3)Exception
这部分你能看到抛出异常的类型。也能得到异常代码和线程。报告越详细你就能得到更多额外的信息。

(4)Threads backtraces
这部分提供了应用的所有线程的 backtrace log。回溯是崩溃发生时的活动帧的列表。它能给你崩溃时的一列被调用的函数。看看下面这句:

2    XYZLib    0x34648e88    0x83000 + 8740  

通常都是这四列:

  1. 帧的号码 - 这个例子中是,2.
  2. 二进制库的名称 - 这个例子中是,XYZLib。
  3. 函数被调用时的地址 - 这个例子中是,0x34648e88。
  4. 第四列被分为了两个子列,一个基地址和偏移量。这里是 0x83000 + 8740,第一个数字指的是文件,第二个指的是文件中的代码行数。

(5)Thread state
这部分提供了在崩溃时的寄存器的值。通常你不需要这部分,因为回溯早已给了你找到问题所需要的信息。

(6)Binary images 这部分列出了崩溃时加载的所有二进制库。

符号化

当你第一次看到崩溃日志回溯时可能会困惑。你需要的是方法名和行数,而不是这种东西:

12  zhxy_soha_HD                      0x009a7594 0x45000 + 9840020  

转换这种十六进制地址为可读方法名和行数的过程就叫做 symbolification(符号化)

你可以通过 Xcode 的 Device 窗口来符号化,它会自动的处理成这样:

12  zhxy_soha_HD                      0x009a7594 -[EAGLView swapBuffers] + 292  

使用 Xcode 来符号化时,它需要访问相匹配的应用包,和那个应用包里生成的 .dSYM 文件。这必须是精确匹配,否则无法完全符号化。

如何确定这两个文件是否匹配?看下面的示例:

获取 crash 文件 UUID:

$ grep --after-context=2 "Binary Images:" zhxy_soha_HD_2015-01-21-064352_p01a018-ph-5c-A501HC53-02.crash
Binary Images:  
0x45000 - 0xc50fff zhxy_soha_HD armv7  <bc1c594b4ecf362082a4e8d435f5c3ec> /var/mobile/Containers/Bundle/Application/E42720D7-1CA1-42F8-853B-97B298A648C2/zhxy_soha_HD.app/zhxy_soha_HD  
0x1fe43000 - 0x1fe66fff dyld armv7s  <b01d37db5b0d3a2ea1ccf17afc40a896> /usr/lib/dyld  

这里的 bc1c594b4ecf362082a4e8d435f5c3ec 就是 crash 文件的 uuid。

获取 app 包的 UUID:

# 在本例中的 .app 文件的 uuid
$ xcrun dwarfdump --uuid zhxy_soha_HD.app/zhxy_soha_HD
UUID: BC1C594B-4ECF-3620-82A4-E8D435F5C3EC (armv7) zhxy_soha_HD.app/zhxy_soha_HD  

比较 UUID :

dwarfdump 得到的 UUID 与 grep 得到的 UUID 不同,前者是大写外加 - 符号。为了更直观你需要把它们转换成相同的格式:

$ xcrun dwarfdump --uuid zhxy_soha_HD.app/zhxy_soha_HD | tr '[:upper:]' '[:lower:]' | tr -d '-'
uuid: bc1c594b4ecf362082a4e8d435f5c3ec (armv7) zhxy_soha_hd.app/zhxy_soha_hd  

现在可以确定它们的 UUID 完全匹配,这时候可以开始符号化了。

如果使用 asto 来符号化也能得到相同的效果。首先把 .app.dSYM.crash 这三个文件放到一个文件夹下,然后执行下句命令:

atos -arch armv7  -o zhxy_soha_HD.app/zhxy_soha_HD -l 0x45000 0x009a7594  

注意 0x45000 0x009a7594 的先后顺序。

另外还有一个方法是使用 Xcode 的 symbolicatecrash 命令来把原始 crash 文件符号化,不过首先你需要设置环境变量:

export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer  

然后在同级目录执行:

/Applications/Xcode.app/Contents/SharedFrameworks/DTDeviceKitBase.framework/Versions/A/Resources/symbolicatecrash original.crash zhxy_soha_HD.app.dSYM > symbol.crash

这就会在根目录生成最终的符号化日志。注意 Xcode 6 与 Xcode 5 的 symbolicatecrash 路径不同。

低内存崩溃

既然低内存崩溃日志与常规崩溃日志不同,那就应该拿出来单独讲讲。:)

当低内存崩溃发生后,在崩溃日志中不会有应用线程的栈跟踪。而是每个进程的内存用量。

低内存崩溃日志类似于这种:

Incident Identifier: 30E46451-53FD-4965-896A-457FC11AD05F  
CrashReporter Key:   5a56599d836c4f867f6eec76afee451bf9ae5f31  
OS Version:          iPhone OS 3.1.3 (7E18)  
Date/Time:           2012-10-17 21:39:06.967 -0400

Free pages:        96  
Wired pages:       10558  
Purgeable pages:   0  
Largest process:   Rage Masters

Processes  
         Name                 UUID                    Count resident pages
    Rage Masters <cc527ca9b51937c5adbe035fe27a7b12>    9320 (jettisoned) (active)
    mediaserverd <3d3800d6acfff050e4d0ed91cbe2467e>     255
     dataaccessd <13d80b2e707acc91f9aa3ec4c715b9cc>     505
         syslogd <8eddddc00294d5615afded36ee3f1b62>      71
            apsd <32070d91b216d806973c8f1b1d8077a4>     171
       securityd <b9e51062610d27f727c5119b8f80dcdf>     243
         notifyd <591dd4dd804b4b8741f52335ea1fa4ab>    2027
      CommCenter <b4b87526ae086bb62c982f1078f43f81>     189
     SpringBoard <324939a437d1cca1fa4af72d9f5d0eba>    2158 (active)
      accessoryd <8f21c8b376d16e2ccb95ed6d21d8317a>      91
         configd <85efd41aceac34ccc0019df76623c7a9>     371
       fairplayd <a2eaf736b3e07c7c9a2c82e9eb893555>      93
   mDNSResponder <df1cd275e4ad434e0575990e8e1da4cb>     292
       lockdownd <80d2bd44c0bcca273d48ce52010f7e65>    1204
         launchd <a5988245aade809bf77576f1d9de42c5>      72

你如果看到 jettisoned ,那它旁边就是被 iOS 清理的进程名称。如果你的应用名称的旁边,那抱歉,它被清理了。

Exception Codes(异常代码)

在每个崩溃报告的异常部分你都会看到异常代码,通常异常代码都是文本开头,紧接着十六进制值。从这些代码中可以看出程序崩溃的原因是内存问题,还是程序问题,或者是其他一些原因导致的。

这里是一些常见的异常代码:

  • 0x8badf00d:读作 "ate bad food"!这个代码表示应用被 iOS 终止了,因为「看门狗」发生了超时。通常是应用消耗了太多时间来启动、终止,或响应系统事件。
  • 0xbad22222:这个代码表示 VoIP 应用被 iOS 终止了,因为它恢复过于频繁。
  • 0xdead10cc:这个读作 "dead lock"!它表示由于一直占用系统资源从而程序被 iOS 终止了。
  • 0xdeadfa11:这个可以读作 "dead fall"!它表示用户强制退出应用。

注意:从后台移除应用不会生成崩溃报告。

总结

每次崩溃的发生其实都是代码的具象化,拥有良好结构的代码能够大大减少崩溃的发生几率。再者,每一个编译警告其实都是编译器对你的关心,所以请认真对待警告,实现出 0 error 0 warning

参考链接:

  1. Demystifying iOS Application Crash Logs
  2. Symbolicating iPhone App Crash Reports
  3. Apple Technical Note TN2151
  4. Apple Technical Q&A QA1765