Objective C - how to programmatically stop execution for debugging, while allowing continuation?
There's a way. It's not an Objective-C thing, it's a Unix thing.
kill(getpid(), SIGSTOP);
or simply:
raise(SIGSTOP);
In Swift:
raise(SIGSTOP)
This will break in the debugger in the __kill
or __pthread_kill
function. You will need to then go up a few stack frames to look at the frame that called kill
or raise
. You can use the debugger`s continue command to resume execution.
Note that if you're not running under the debugger and you execute this, your app will just hang. Take a look at [Technical Q&A QA1631: Detecting the Debugger](http://developer.apple.com/library/mac/#qa/qa1361/_index.html. You can use that information to write a wrapper function or macro that only sends SIGSTOP
when running under the debugger. This answer may help.
Also, the Foundation framework provides a different assert macro for use in regular functions. It's NSCAssert
.
Sounds like you want to use Conditional Breakpoints. If you set a breakpoint by clicking in the margin of your source code, then ctrl-click the little blue breakpoint thing, you can edit some options, including making the breakpoint conditional on the value of a variable.
Here's a blog post with some screenshots and more info.
This Stack Overflow question has some good pointers, too.
If you insist on triggering the breakpoint programmatically, then write a function and put a breakpoint inside it:
void MyConditionalBreak(BOOL condition, NSString *comment)
{
if (condition) {
NSLog(@"Stopped because %@", comment); // SET BREAKPOINT ON THIS LINE
}
}
Then you can call this function in a similar manner to NSAssert. If you declare the function in your project's precompiled header file (Whatever.pch) it will be available in all of your source files, without having to explicitly #import
anything.
Here is how I do it:
First, in breakpoints tab I set my apps to break if any exception is raised:
Then In code (I usually have common header file containing common definitions like this that I import everywhere):
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__]); }
Now, You can use it like NSAssert, but instead of killing your app, you merely trigger a breakpoint:
MYAssert(bEverythingOkay, @"Something went wrong!");
// Or with arguments of course
MYAssert(bEverythingOkay, @"Something went wrong (TestValue=%zd; Reason=%@)", myTestValue, [this getLastError]);