在使用Objective C中的标准NSAssert(condition_which_should_evaluate_true,@“错误消息”)语句并在“All Exceptions”断点中添加一个“All Exceptions”断点时,我已成功地使用我的调试版本来停止执行条件。断点导航器。
嗯,好,但是大部分时间我在调试时,我还希望在那之后继续正常的程序执行。在断言失败后继续执行该程序有助于追踪混淆/错误的来源。至少就我记得在不同平台上编程时的记忆而言。
在Objective C开发中是否有标准的方法?
答案 0 :(得分:14)
有办法。它不是Objective-C的东西,它是Unix的东西。
kill(getpid(), SIGSTOP);
或简单地说:
raise(SIGSTOP);
这将在__kill
函数的调试器中中断。然后,您需要沿着一两帧堆栈来查看调用kill
的帧。您可以使用debugger的continue命令继续执行。
请注意,如果您没有在调试器下运行并执行此操作,那么您的应用就会挂起。看看Technical Q&A QA1631: Detecting the Debugger。您可以使用该信息编写在调试器下运行时仅发送SIGSTOP
的包装函数或宏。
此外,Foundation框架提供了一个不同的断言宏,可用于常规函数。它是NSCAssert
。
答案 1 :(得分:2)
听起来你想使用条件断点。如果通过单击源代码的边距来设置断点,然后按住Ctrl键单击蓝色小断点,可以编辑一些选项,包括使断点以变量值为条件。
这是一个blog post with some screenshots和更多信息。
This Stack Overflow question也有一些很好的指示。
如果你坚持以编程方式触发断点,那么编写一个函数并在其中放置一个断点:
void MyConditionalBreak(BOOL condition, NSString *comment)
{
if (condition) {
NSLog(@"Stopped because %@", comment); // SET BREAKPOINT ON THIS LINE
}
}
然后您可以以与NSAssert类似的方式调用此函数。如果在项目的预编译头文件(Whatever.pch)中声明该函数,它将在所有源文件中可用,而不必明确#import
任何内容。
答案 2 :(得分:2)
我是这样做的:
首先,在断点选项卡中,如果引发任何异常,我会将我的应用设置为中断:
然后在代码中(我通常有一个包含常见定义的公共头文件,我随处导入):
static void ThrowException(NSString* reason)
{
@try
{
@throw [NSException
exceptionWithName:@"DebugAssertionException"
reason:reason
userInfo:nil];
}
@catch (NSException * e)
{
NSLog(@"%@", e);
}
}
#define MYAssert(test, fmt, ...) if (!(test)) { ThrowException([NSString stringWithFormat:@"%s !!! ASSERT !!! " fmt, __PRETTY_FUNCTION__, ##__VA_ARGS__]); }
现在,您可以像使用NSAssert一样使用它,但不是杀死您的应用程序,而只是触发断点:
MYAssert(bEverythingOkay, @"Something went wrong!");
// Or with arguments of course
MYAssert(bEverythingOkay, @"Something went wrong (TestValue=%zd; Reason=%@)", myTestValue, [this getLastError]);
答案 3 :(得分:1)
我绝不是这个领域的专家,但我使用的代码可以通过键盘输入进入调试器。
github上的domesticcatsoftware的DCIntrospect就是这样做的。
查看其主要文件DCIntrospect.m的顶部,看看它是如何做到的。
它引用了一些来源,但根据我的经验,它可以在armv6 / 7和模拟器上进入调试器所需的当前程序集是最新的
外部参考资料以获取更多背景信息
答案 4 :(得分:1)
不确定为什么没有其他人给出明确的直截了当的答案......已经过了五年但迟到总比没有好。
#ifdef DEBUG
#define manualBreakpoint() \
NSLog(@"\n\n\
Breakpoint called on: \n\n\
File: %s \n\n\
Line number: %i", __FILE__, __LINE__);\
\
raise(SIGSTOP)
#else
#define manualBreakpoint() ;
#endif
要使用它,只需输入以下内容:manualBreakpoint();
这将在调用该代码时暂停应用程序并在堆栈跟踪中显示当前方法(以及记录您的应用程序已暂停的文件名和行号)IFF您处于调试模式,如果您在appstore的生产模式(又名发布,发布或存档)它什么都不做。
答案 5 :(得分:0)
使用Rob的评论,以及“ios5编程:推动限制”和Lumberjack框架中的一些想法,这里有一个宏来让调试器停止并允许在DEBUG
构建中的断言期间继续,但是否则就像在RELEASE
(或实际上任何非-DEBUG
)构建期间一样。
#ifdef DEBUG
#define MyAssert(condition, desc, ...) \
if (!(condition)) { \
NSLog((desc), ## __VA_ARGS__); \
if (AmIBeingDebugged()) \
kill (getpid(), SIGSTOP); \
else { \
NSLog(@"%@, %d: could not break into debugger.", THIS_FILE, __LINE__); \
} \
}
#define MyCAssert(condition, desc, ...) \
if (!(condition)) { \
NSLog((desc), ## __VA_ARGS__); \
if (AmIBeingDebugged()) \
kill (getpid(), SIGSTOP); \
else \
NSLog(@"%@, %d: could not break into debugger.", THIS_FILE, __LINE__)); \
} \
}
#else //NOT in DEBUG
#define MyAssert(condition, desc, ...) \
if (!(condition)) { \
DDLogError((desc), ## __VA_ARGS__); \ //use NSLog if not using Lumberjack
NSAssert((condition), (desc), ## __VA_ARGS__); \
}
#define MyCAssert(condition, desc, ...) \
if (!(condition)) { \
DDLogError((desc), ## __VA_ARGS__); \ //use NSLog if not using Lumberjack
NSCAssert((condition), (desc), ## __VA_ARGS__); \
}
#endif //end DEBUG
#endif
这些宏需要函数AmIBeingDebugged()
,您可以通过Rob给出的链接从Apple获得:技术Q& A QA1631:检测调试器。 (您还需要在构建设置中定义DEBUG
。)
请注意,我在非DDLogError()
构建中选择了Lumberjack的NSLog()
而不是DEBUG
,因为它会吐出致命断言发生的方法,文件和行号。
答案 6 :(得分:0)
如果你想使用控制台,一个简单的技巧是:
if (!condition_which_should_evaluate_true) {
; // Put breakpoint here
}
然后将断点放在该行内。如果条件的计算结果为NO,则调用断点。