我在 iOS 5 模拟器/设备中调试 Xcode 4.2 时遇到问题。以下代码按预期崩溃:
NSArray *arr=[NSArray array];
[arr objectAtIndex:100];
在 iOS 4 中,我得到了一个有用的十六进制数字堆栈跟踪。但在 iOS 5 中,它只给了我:
*** First throw call stack:
(0x16b4052 0x1845d0a 0x16a0674 0x294c 0x6f89d6 0x6f98a6 0x708743 0x7091f8 0x7fcaa9 0x2257fa9 0x16881c5 0x15ed022 0x15eb90a 0x15eadb4 0x15eaccb 0x6f02a7 0x6faa93 0x2889 0x2805)
谢谢。
我尝试过的任何方法都无法解决此问题(尝试了两个编译器、两个调试器等)。在为 iOS 5 更新升级 XCode 之后,似乎没有堆栈跟踪工作。
但是,我找到了一种有效的解决方法——创建我自己的异常处理程序(这对于其他原因也很有用)。首先,创建一个函数来处理错误并将其输出到控制台(以及您想要对其执行的任何其他操作):
void uncaughtExceptionHandler(NSException *exception) {
NSLog(@"CRASH: %@", exception);
NSLog(@"Stack Trace: %@", [exception callStackSymbols]);
// Internal error reporting
}
接下来,将异常处理程序添加到您的应用程序委托中:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
// Normal launch stuff
}
而已!
如果这不起作用,那么只有两个可能的原因:
有些东西正在覆盖您的 NSSetUncaughtExceptionHandler 调用(整个应用程序只能有一个处理程序)。例如,一些 3rd 方库设置了自己的 uncaughtExceptionHandler。因此,请尝试在您的 didFinishLaunchingWithOptions 函数的末尾设置它(或有选择地禁用第 3 方库)。或者更好的是,在 NSSetUncaughtExceptionHandler 上设置一个符号断点以快速查看是谁在调用它。您可能想要做的是修改您当前的而不是添加另一个。您实际上并没有遇到异常(例如, EXC_BAD_ACCESS 不是异常;感谢@Erik B 的评论,如下)
有一个添加异常断点的有用选项(使用断点导航器底部的 +)。这将在任何异常上中断(或者您可以设置条件)。我不知道这个选择是 4.2 中的新选项,还是我最终才注意到它试图解决缺少符号的问题。
一旦你命中了这个断点,你就可以像往常一样使用 Debug Navigator 来导航调用堆栈、检查变量等。
如果您确实想要一个适合复制/粘贴等的符号化调用堆栈,gdb 回溯将从那里正常工作:
(gdb) bt
#0 0x01f84cf0 in objc_exception_throw ()
#1 0x019efced in -[NSObject doesNotRecognizeSelector:] ()
(ETC)
调试器上有一个新功能。您可以在抛出异常时设置断点并在此处停止执行,就像它过去在 4.0 上发生的那样。
在“断点导航器”上,添加一个“异常断点”,然后在选项弹出窗口中按“完成”。
就这样!
PS:在某些情况下,仅针对 Objective-C 异常进行中断会更好。
这是另一种解决方案,不像以前那么优雅,但如果你没有添加异常断点或处理程序,它可能只是一种方法。
当应用程序崩溃,你得到你的原始第一次抛出调用堆栈(十六进制数字),输入 Xcode 控制台 info line *hex
(不要忘记星号和 0x
十六进制说明符),例如:
(gdb) info line *0x2658
Line 15 of "path/to/file/main.m" starts at address 0x25f2 <main+50>
and ends at 0x267e <main+190>.
如果您使用 lldb,您可以输入 image lookup -a hex
(在这种情况下不带星号),您会得到类似的输出。
使用此方法,您可以从抛出堆栈顶部(大约有 5-7 个系统异常传播器)遍历导致崩溃的函数,并确定确切的文件和代码行。
此外,为了获得类似的效果,您可以在终端中使用 atos 实用程序,只需键入:
atos -o path/to/AplicationBundle.app/Executable 0xAdress1 0xAdress2 0xAdress3 ...
你会得到符号化的堆栈跟踪(至少对于你有调试符号的函数)。这种方法更可取,因为您不需要为每个地址调用 info line
,只需从控制台输出复制地址并将它们粘贴到终端。
您可以添加 Exception Breakpoint(使用 Breakpoint Navigator 底部的 +)并向其添加操作 bt
(单击 Add Action 按钮,选择 Debugger命令,在文本字段中输入“bt”)。一旦抛出异常,这将显示堆栈跟踪。
这是一个常见问题,在 4.2 中没有获取堆栈跟踪。您可以尝试在 LLDB 和 GDB 之间进行交换,看看是否可以获得更好的结果。
在此处提交错误报告。
http://developer.apple.com/bugreporter/
编辑:
我相信,如果您换回 LLVM GCC 4.2,您将不会看到这种情况发生。你可能会失去你需要的功能。
在您的主要功能中使用此代码:
int main(int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int retVal;
@try {
retVal = UIApplicationMain(argc, argv, nil, nil);
}
@catch (NSException *exception) {
NSLog(@"CRASH: %@", exception);
NSLog(@"Stack Trace: %@", [exception callStackSymbols]);
}
@finally {
[pool release];
}
return retVal;
}
在 Xcode 的调试控制台提示符下输入:
图像查找-a 0x1234
它会向您显示类似的内容:
Address: MyApp[0x00018eb0] (MyApp.__TEXT.__text + 91088)
Summary: MyApp`-[MyViewController viewDidAppear:] + 192 at MyViewController.m:202
重新打开“Compile for Thumb”(调试配置)对我有用。
不定期副业成功案例分享
uncaughtExceptionHandler
例程从未被调用。