(见底部更新)
最近,当我的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,但崩溃发生在1.0和1.1版本的TestFlight上,而且我已经使用前者已经有一段时间了,没有这样的问题。
所以,总结一下,我不知道为什么会出现这种崩溃,它是什么来的。有什么想法吗?
更新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
,然后崩溃EXC_BAD_ACCESS
1}}在objc_msgSend + 16
中,就像我原来的崩溃一样。
所以这只是意味着有人注册了UIApplicationResumedNotification
的观察者并且在观察者被解除分配之前没有删除它。基于我从未注册过此类通知的事实,我可以认为这次崩溃不是我的错。问题仍然存在 - 那是谁呢?我想知道究竟谁注册了这个通知......
更新2
虽然我还在等着看我的应用程序的新版本是否有任何关于此错误的更改,但由于此原因导致我的先前版本出现了另一次崩溃。事实证明,UIApplicationResumedNotification
的任何寄存器都为它指定了选择器_applicationResuming:
。我怀疑这有什么用处。
答案 0 :(得分:6)
我在运行IOS 6.0.1的设备的崩溃报告中有完全相同的堆栈跟踪。我设法通过以下模式在Simulator上重现问题:
经过大量调试后,我发现 _applicationResuming:消息被发送到 UITextField ,我将其作为对Memory Warning的反应而发布。我在IOS 5.1下测试了相同的模式,但它没有导致崩溃。出于某些原因,IOS 6 UITextField注册了ApplicationResumeEvent(可能并不总是在键盘出现后)。
我的解决方法是在释放它之前从NSNotificationCenter中删除该对象:
[[NSNotificationCenter defaultCenter] removeObserver:self.placeFld];
self.placeFld = nil;
答案 1 :(得分:3)
我刚遇到此问题并找到了一个不涉及删除通知的解决方案。在我们的例子中,有一些旧代码正在执行此操作:
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
[searchBar resignFirstResponder];
// other stuff
}
我不知道为什么我们有这个,但它现在已经消失了,崩溃消失了。看来,在这种情况下,当searchBarTextDidBeginEditing被调用时,在搜索栏的文本编辑字段上调用孤立的第一响应者,然后一旦拥有此UISearchBar的视图控制器被解除分配,我们就会崩溃,我们做了后台/前台舞。
YMMV
答案 2 :(得分:2)
在-[NSNotificationCenter postNotificationName:object:userInfo:]
上放置一个断点。它试图向一个不再存在的对象发送通知,或类似的东西。您可能会错误管理自己的通知或自己的对象。
如果您尚未使用它,请考虑切换到ARC。
使用静态分析仪。它可以找到潜在的内存问题。
答案 3 :(得分:1)
可能有很多东西,但我认为检查注册任何UIApplication通知的代码会更好。您实际上并不知道哪个通知会触发错误。
此外,是否有任何对象在AppDelegate上保留/持有强大的参考?这可能会导致一些奇怪的保留周期,从而导致崩溃。
我从未见过XCode行为不端造成的这种崩溃。
编辑:粘贴头文件中的所有通知。可能有点矫枉过正,但有些可以通过app resume / from background
发送UIKIT_EXTERN NSString *const UIApplicationDidEnterBackgroundNotification NS_AVAILABLE_IOS(4_0);
UIKIT_EXTERN NSString *const UIApplicationWillEnterForegroundNotification NS_AVAILABLE_IOS(4_0);
UIKIT_EXTERN NSString *const UIApplicationDidFinishLaunchingNotification;
UIKIT_EXTERN NSString *const UIApplicationDidBecomeActiveNotification;
UIKIT_EXTERN NSString *const UIApplicationWillResignActiveNotification;
UIKIT_EXTERN NSString *const UIApplicationDidReceiveMemoryWarningNotification;
UIKIT_EXTERN NSString *const UIApplicationWillTerminateNotification;
UIKIT_EXTERN NSString *const UIApplicationSignificantTimeChangeNotification;
UIKIT_EXTERN NSString *const UIApplicationWillChangeStatusBarOrientationNotification; // userInfo contains NSNumber with new orientation
UIKIT_EXTERN NSString *const UIApplicationDidChangeStatusBarOrientationNotification; // userInfo contains NSNumber with old orientation
UIKIT_EXTERN NSString *const UIApplicationStatusBarOrientationUserInfoKey; // userInfo dictionary key for status bar orientation
UIKIT_EXTERN NSString *const UIApplicationWillChangeStatusBarFrameNotification; // userInfo contains NSValue with new frame
UIKIT_EXTERN NSString *const UIApplicationDidChangeStatusBarFrameNotification; // userInfo contains NSValue with old frame
UIKIT_EXTERN NSString *const UIApplicationStatusBarFrameUserInfoKey; // userInfo dictionary key for status bar frame
UIKIT_EXTERN NSString *const UIApplicationLaunchOptionsURLKey NS_AVAILABLE_IOS(3_0); // userInfo contains NSURL with launch URL
UIKIT_EXTERN NSString *const UIApplicationLaunchOptionsSourceApplicationKey NS_AVAILABLE_IOS(3_0); // userInfo contains NSString with launch app bundle ID
UIKIT_EXTERN NSString *const UIApplicationLaunchOptionsRemoteNotificationKey NS_AVAILABLE_IOS(3_0); // userInfo contains NSDictionary with payload
UIKIT_EXTERN NSString *const UIApplicationLaunchOptionsLocalNotificationKey NS_AVAILABLE_IOS(4_0); // userInfo contains a UILocalNotification
UIKIT_EXTERN NSString *const UIApplicationLaunchOptionsAnnotationKey NS_AVAILABLE_IOS(3_2); // userInfo contains object with annotation property list
UIKIT_EXTERN NSString *const UIApplicationProtectedDataWillBecomeUnavailable NS_AVAILABLE_IOS(4_0);
UIKIT_EXTERN NSString *const UIApplicationProtectedDataDidBecomeAvailable NS_AVAILABLE_IOS(4_0);
UIKIT_EXTERN NSString *const UIApplicationLaunchOptionsLocationKey NS_AVAILABLE_IOS(4_0); // app was launched in response to a CoreLocation event.
UIKIT_EXTERN NSString *const UIApplicationLaunchOptionsNewsstandDownloadsKey NS_AVAILABLE_IOS(5_0); // userInfo contains an NSArray of NKAssetDownlo
答案 4 :(得分:0)
在调试奇怪的事故之前,我要做的一些事情是清除卡座。
构建清理(删除本地缓存文件)。
从模拟器/设备中删除应用程序(有时会缓存XIB)。
重新启动Xcode(当Xcode与当前设置不同步时,会出现一些奇怪的错误。)
然后,再试一次。