(请参见底部更新)
最近,我的iPhone应用程序在返回后台时出现了一个奇怪且罕见的崩溃。崩溃日志只包含系统调用:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x00000138
Crashed Thread: 0
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 libobjc.A.dylib 0x34c715b0 objc_msgSend + 16
1 CoreFoundation 0x368b7034 _CFXNotificationPost + 1424
2 Foundation 0x34379d8c -[NSNotificationCenter postNotificationName:object:userInfo:] + 68
3 UIKit 0x37ddfec2 -[UIApplication _handleApplicationResumeEvent:] + 1290
4 UIKit 0x37c37d5c -[UIApplication handleEvent:withNewEvent:] + 1288
5 UIKit 0x37c376d0 -[UIApplication sendEvent:] + 68
6 UIKit 0x37c3711e _UIApplicationHandleEvent + 6150
7 GraphicsServices 0x36dea5a0 _PurpleEventCallback + 588
8 CoreFoundation 0x3693b680 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 12
9 CoreFoundation 0x3693aee4 __CFRunLoopDoSources0 + 208
10 CoreFoundation 0x36939cb2 __CFRunLoopRun + 642
11 CoreFoundation 0x368aceb8 CFRunLoopRunSpecific + 352
12 CoreFoundation 0x368acd44 CFRunLoopRunInMode + 100
13 GraphicsServices 0x36de92e6 GSEventRunModal + 70
14 UIKit 0x37c8b2fc UIApplicationMain + 1116
15 [MyAppName] 0x00083d60 main (main.m:20)
16 [MyAppName] 0x00080304 start + 36
这可能看起来像是在UIApplicationWillEnterForegroundNotification
或UIApplicationDidBecomeActiveNotification
上调用了一个僵尸对象(根据堆栈跟踪中的_handleApplicationResumeEvent
和崩溃时间猜测),但是:
- 我的任何类都没有注册
UIApplicationDidBecomeActiveNotification
,只有一些永远存在的单例注册了UIApplicationWillEnterForegroundNotification
; - 我进行了一些实验,结果发现发布
UIApplicationWillEnterForegroundNotification
从[UIApplication _sendWillEnterForegroundCallbacks:]
发送,并且在崩溃日志中没有出现。
对我来说,所有这些意味着我使用的某个库中存在错误,或者是系统错误,并且崩溃在iOS 5.1.1(发布构建)、iOS 6.0(发布构建)和iOS 6.0(调试构建)上发生过一次。我扫描了我正在使用并且可以访问源代码的每个库,它们既不注册UIApplicationWillEnterForegroundNotification
也不注册UIApplicationDidBecomeActiveNotification
。我无法访问的唯一库是TestFlight,但是崩溃发生在TestFlight的1.0和1.1版本上,并且我已经使用前者很长一段时间了,没有出现这样的问题。
总之,我不知道为什么会出现这个崩溃以及它来自哪里。有什么想法吗?
更新1
我通过使用通知中心回调和记录堆栈跟踪来更深入地调查了这个问题,感谢DarthMike和matt的帮助。我发现当UIApplicationResumedNotification
通知作为从后台返回的一部分被触发时,就会出现这个确切的堆栈。猜猜——它是一些“私有”通知,并且它没有公共标识符对应物。它没有userInfo
,其对象是UIApplication
(与许多在此之前发布的其他通知相同)。显然,我不使用它,我可以访问源代码的任何库也不使用它。我甚至找不到在互联网上合理的提及!我也非常怀疑TestFlight是罪魁祸首,因为崩溃在调试模式下也会发生,而我不会在调试模式下“起飞”TestFlight。
这是接收UIApplicationResumedNotification
的堆栈跟踪。偏移量都相同,但是具有恒定的字节偏移量(根据库的不同为2或4,可能是因为它是调试堆栈跟踪而不是发布):
0 [MyAppName] 0x0016f509 NotificationsCallback + 72
1 CoreFoundation 0x3598ce25 __CFNotificationCenterAddObserver_block_invoke_0 + 124
2 CoreFoundation 0x35911037 _CFXNotificationPost + 1426
3 Foundation 0x333d3d91 -[NSNotificationCenter postNotificationName:object:userInfo:] + 72
4 UIKit 0x36e39ec7 -[UIApplication _handleApplicationResumeEvent:] + 1294
5 UIKit 0x36c91d61 -[UIApplication handleEvent:withNewEvent:] + 1292
6 UIKit 0x36c916d5 -[UIApplication sendEvent:] + 72
7 UIKit 0x36c91123 _UIApplicationHandleEvent + 6154
8 GraphicsServices 0x35e445a3 _PurpleEventCallback + 590
9 CoreFoundation 0x35995683 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 14
10 CoreFoundation 0x35994ee9 __CFRunLoopDoSources0 + 212
11 CoreFoundation 0x35993cb7 __CFRunLoopRun + 646
12 CoreFoundation 0x35906ebd CFRunLoopRunSpecific + 356
13 CoreFoundation 0x35906d49 CFRunLoopRunInMode + 104
14 GraphicsServices 0x35e432eb GSEventRunModal + 74
15 UIKit 0x36ce5301 UIApplicationMain + 1120
16 [MyAppName] 0x000aa603 main + 390
17 [MyAppName] 0x000a41b0 start + 40
NotificationsCallback是一个“观察者”回调,我暂时只是为了调试添加的。
为了证明一点,我故意从我的某个对象中省略了一次removeObserver:调用,以生成一个僵尸/异常,并且堆栈跟踪仍然包括_CFXNotificationPost + 1426 ,接着就是带有objc_msgSend + 16的EXC_BAD_ACCESS崩溃,就像原始崩溃一样。 这意味着有人为UIApplicationResumedNotification注册了一个观察者,在观察者被释放之前没有将其删除。基于我从未注册过这样的通知这个事实,我可以认为这个崩溃不是我的错。但问题仍然存在——那么是谁的责任呢?我想知道到底是谁注册了这个通知...
更新2
虽然我仍在等待看看在我的应用程序的新版本中是否有任何更改,但我在之前的版本中又遇到了由此引起的崩溃。结果发现,无论是什么为UIApplicationResumedNotification注册,都会为其指定选择器_applicationResuming:。不过,我怀疑这没什么用处。