在 Objective-C 和 Xcode 中抛出的调试异常
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/711650/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Debugging exception thrown in Objective-C and Xcode
提问by rtemp
I am a long time Microsoft developer and I am new to iPhone development using Xcode. So, I am reading a book and going through examples trying to teach myself how to write an iPhone application using Objective-C. All has been good so far, however, once in a while I run into the generic 'objc_exception_throw
' message at runtime. When this happens, the source of this exception is very difficult to find. After some trial and error I found my answer. One of the parameters was misspelled.
我是 Microsoft 的长期开发人员,而且我是使用 Xcode 进行 iPhone 开发的新手。因此,我正在阅读一本书并通过示例尝试自学如何使用 Objective-C 编写 iPhone 应用程序。到目前为止,一切都很好,但是,我偶尔会objc_exception_throw
在运行时遇到通用的“ ”消息。发生这种情况时,很难找到此异常的来源。经过一些试验和错误,我找到了我的答案。其中一个参数拼写错误。
As you can see below, I misspelled the 'otherButtonTitles' parameter by leaving out the second 't' in button.
正如您在下面看到的,我通过遗漏按钮中的第二个 't' 拼错了 'otherButtonTitles' 参数。
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:@"Date and Time Selected"
message:message
delegate:nil
cancelButtonTitle:@"Cancel"
otherButonTitles:nil];
The reason this took me time to find is that the code built successfully. Is this normal behavior for the Objective-C compiler? I am used to having the build fail in the .NET compiler when I make a common syntax error like this. Is there a compiler setting I can change to make the built fail when I make these mistakes?
这花了我时间才找到的原因是代码构建成功。这是 Objective-C 编译器的正常行为吗?当我犯这样的常见语法错误时,我习惯于在 .NET 编译器中构建失败。当我犯这些错误时,是否可以更改编译器设置以使构建失败?
回答by lhunath
First and foremost, open ~/.gdbinit
(that's the file called .gdbinit
in your home directory - yes, starts with a dot) and put this in it:
首先,打开~/.gdbinit
(这是.gdbinit
在您的主目录中调用的文件- 是的,以点开头)并将其放入其中:
fb -[NSException raise]
fb objc_exception_throw
fb malloc_error_break
That'll initialize GDB with three default breakpoints, when they occur, GDB will halt your application and show you the stack trace. This is very well integrated with Xcode so you'll be able to nicely walk through your code by clicking stack trace elements as soon as an exception occurs somewhere or a malloc fails.
这将使用三个默认断点初始化 GDB,当它们发生时,GDB 将停止您的应用程序并向您显示堆栈跟踪。这与 Xcode 集成得非常好,因此只要某处发生异常或 malloc 失败,您就可以通过单击堆栈跟踪元素来很好地浏览代码。
Then, open the Get Info
panel on your project (or select your project (top item in the Groups & Files
) and hit cmd-i
), go to the Build
tab and set your project's Base SDK
to Device - iPhone OS [someversion]
. Scroll all the way to the bottom and find the GCC 4.0 - Warnings
section. There; turn on as many warnings as you feel comfortable with, but make sure to turn on Treat Warnings as Errors
(this is the equivalent of GCC_TREAT_WARNINGS_AS_ERRORS
). Personally, I have it set to this:
然后,打开Get Info
您项目的面板(或选择您的项目(在 中的顶部项目Groups & Files
)并点击cmd-i
),转到Build
选项卡并将您的项目设置Base SDK
为Device - iPhone OS [someversion]
。一直滚动到底部并找到该GCC 4.0 - Warnings
部分。那里; 打开尽可能多的警告,但请确保打开Treat Warnings as Errors
(这相当于GCC_TREAT_WARNINGS_AS_ERRORS
)。就个人而言,我已将其设置为:
(source: lyndir.com)
(来源:lyndir.com)
You should now be getting compiler warnings for most things you can do wrong in code and the compiler won't let you run the code until you fix them. When things do get past the compiler's nose, you should be able to find the problem easily with GDB breaking at a convenient spot.
您现在应该会收到编译器警告,提示您在代码中可能做错的大多数事情,并且在您修复它们之前,编译器不会让您运行代码。当事情确实超越了编译器的鼻子时,您应该能够通过 GDB 在方便的位置中断轻松找到问题。
You should also look into NSZombie*
. These are environment variables that are very handy for early breaking on bad memory allocation or access situations. For instance; wih NSZombieEnabled
nothing will truly be released; on dealloc it'll get overwritten with _NSZombie
and should you try to access this dealloced memory again (dereferencing a dealloced pointer) you'll get something to break on in GDB, instead of the call going through like normal, only being issued on random data (which, of course, isn't what you wanted). For more info on this, see http://www.cocoadev.com/index.pl?NSZombieEnabled.
您还应该查看NSZombie*
. 这些环境变量对于早期中断内存分配或访问情况非常方便。例如; 王氏NSZombieEnabled
什么都不会真正被释放; 在 dealloc 上它会被覆盖,_NSZombie
如果你再次尝试访问这个释放的内存(取消引用一个释放的指针)你会在 GDB 中得到一些东西,而不是像平常一样调用,只在随机数据上发出(当然,这不是您想要的)。有关这方面的更多信息,请参阅http://www.cocoadev.com/index.pl?NSZombieEnabled。
回答by Matt Gallagher
Always use the -Werror
GCC setting (GCC_TREAT_WARNINGS_AS_ERRORS = YES
). You should never have warnings in your code and this is an example where the warning is a critical error.
始终使用-Werror
GCC 设置 ( GCC_TREAT_WARNINGS_AS_ERRORS = YES
)。你的代码中永远不应该有警告,这是一个警告是严重错误的例子。
Also, if you get an objc_exception_throw
, switch to the console (Command-shift-R) and look for the first "low" number address.
此外,如果您收到objc_exception_throw
,请切换到控制台(Command-shift-R)并查找第一个“低”数字地址。
2009-04-01 13:25:43.385 CrashExample[41720:20b] Stack: (
2528013804,
2478503148,
2528036920,
2528053460,
2358032430,
11076,
11880,
816174880,
345098340,
145973440,
816174880,
)
In this case it would be "11076". So type in the console:
在这种情况下,它将是“11076”。所以在控制台输入:
info line *11076
That will tell you the line in your code where the exception was thrown.
这将告诉您代码中抛出异常的行。
回答by drewh
Misspelled parameters should generally result in a "Warning: such-and-such object does not respond to selector x" in yellow at the line in question. I believe this is on by default, as I didn't have to change any compiler settings to see these.
拼写错误的参数通常会在相关行以黄色显示“警告:某某对象不响应选择器 x”。我相信这是默认情况下,因为我不必更改任何编译器设置来查看这些。
Also, when I encounter an uncaught exception, it's sometimes beneficial to drop into the gdb console (should come up when you execute your app) and type the following to get backtraces for all threads:
此外,当我遇到未捕获的异常时,有时进入 gdb 控制台(在您执行应用程序时应该出现)并键入以下内容以获取所有线程的回溯是有益的:
t a a bt
TABT
回答by Chris Lundie
What you did is not a compile-time error, because the Objective-C runtime checks at runtime if an object can respond to the message you send to it.
您所做的不是编译时错误,因为 Objective-C 运行时会在运行时检查对象是否可以响应您发送给它的消息。
I recommend adding this build setting to your target or project:
我建议将此构建设置添加到您的目标或项目:
GCC_TREAT_WARNINGS_AS_ERRORS = YES
回答by Kendall Helmstetter Gelner
The reason it's not a compilation error, is because it's perfectly valid to send a message not known at compile time to any object (and any object can be configured to handle messages dynamically as well). All method calls are really messages being sent to objects.
它不是编译错误的原因是,将编译时未知的消息发送到任何对象是完全有效的(并且任何对象也可以配置为动态处理消息)。所有方法调用实际上都是发送给对象的消息。
In general, if you see any warnings you should address them, as in most cases they can lead to problems (as you saw). The misleading aspect is here is that if you compile a file once and it has only warnings, if you compile other classes without making changes to the class that has warnings, the warning will not show in the compiler messages. So every now and then you may want to "clean all targets" and build again to make sure you didn't miss any warnings.
一般来说,如果您看到任何警告,您应该解决它们,因为在大多数情况下它们会导致问题(如您所见)。误导性的方面是,如果您编译一个文件一次并且它只有警告,如果您编译其他类而不对有警告的类进行更改,则警告将不会显示在编译器消息中。因此,您可能会时不时地“清理所有目标”并重新构建,以确保您不会错过任何警告。