catch exceptions in iOS main Runloop - ios

UIApplication catch the exceptions in main run loop and rethrow it, for Mac, NSApplication has a reportException: which can get the NSException object, UIApplication does not provide this method. Is there similar thing which be used on iOS.
the exception is caught by UIApplication and rethrow it, then it becomes a C++ exception. NSSetUncaughtExceptionHandler can not catch it.
about reportException:, you can refer http://www.cocoabuilder.com/archive/cocoa/7540-catching-exceptions-in-applications.html

Related

iOS: Setting up a Mach exception handler without interfering with LLDB

I'm using the library called CwlPreconditionTesting which is used to test Swift assertions. It uses Mach exceptions handler API to catch exceptions that's available on iOS and OS X.
The library works well in simulators, but devices aren't supported by it. The reason for this is that on devices, the Swift assert functions (e.g. fatalError) crash with EXC_BREAKPOINT exception type, which is also the exception type the debugger uses when someone puts a breakpoint somewhere and the debugger wants to suspend the program. The underlying assembly instruction is brk.
I wanted to add device tests support to the library, but after setting up the exception handler, if the debugger reaches a breakpoint I added manually, the debugger just hangs. To bypass this, I tried to make the exception handler forward the handling of the exception to the debugger.
When I implement an exception handler, if it returns with a failure (i.e. anything other than KERN_SUCCESS), the kernel should forward it to the next exception handler in line, the debugger in my case. I didn't find any official documentation on this, but it says so here and in a piece of code from Mike Ash's blog:
// Handle EXCEPTION_DEFAULT behavior
kern_return_t catch_mach_exception_raise (mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
mach_exception_data_t code,
mach_msg_type_number_t codeCnt)
{
// Do smart stuff here.
fprintf(stderr, "My exception handler was called by exception_raise()\n");
// Inform the kernel that we haven't handled the exception, and the
// next handler should be called.
return KERN_FAILURE;
}
Even if I always return KERN_FAILURE, the debugger hangs when I pause at a breakpoint. Here's a screenshot from the Variables View in Xcode, which loads indefinitely:
Is there a way to set up an exception handler and live in peace with LLDB?

NSAssert not work in uiwebview delegate method

In a UIWebView's delegate method webView:shouldStartLoadWithRequest:navigationType:, I put an NSAssert there, but it just output a log, instead of terminating. Here is my code:
- (BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType
{
NSAssert(NO,#"assertion in delegate");
return YES;
}
and the output:
*** WebKit discarded an uncaught exception in the webView:decidePolicyForNavigationAction:request:frame:decisionListener: delegate: assertion in delegate
NSAssert raises an Objective-C exception and these can be caught, so it doesn't guarantee your program will be aborted. Using it in your own code is generally fine, but if your code is called by a framework - such as when a delegate is invoked - it depends on what the framework does. As you have discover WebKit catches exceptions and discards or handles them itself.
The simple solution is to use the standard assert() function. This takes a single Boolean expression and will abort the program printing out the expression, file name and line number of the assertion. This function does not use Objective-C exceptions, it uses the standard abort() function, and so cannot be caught.
HTH
Failed NSAsserts raise ObjC exceptions. (NSInternalInconcistencyException to be precise.) Anyone can install exception handlers or other mechanisms to define what happens to exceptions that are raised in code that they call. And those mechanisms don't have to include halting the process (though continuing after an exception is generally not a great idea).
When you raise ObjC exceptions in a callback, you're not guaranteed that execution will terminate as a result — you're at the mercy of whatever exception handling was set up by the code that called you. If you want to bring the whole process crashing down due to some failure in delegate code, it's probably best to abort() it yourself.

Is it possible to determine if an Objective-C exception will be caught?

I'm running into a situation in iOS (and OS X) where exceptions from NSKeyedUnarchiver cause binary-only third-party frameworks to crash my app (when deployed in the field) when they try to unarchive a corrupt archive, thus forcing users to delete and reinstall the app. This doesn't happen often, but I'd like that number to be zero.
I can't solve the problem by wrapping the NSKeyedUnarchiver calls, both because I don't have the source code and because those calls are not the direct result of anything that my code does; they run on arbitrary background threads at arbitrary times.
I'm currently swizzling the NSKeyedUnarchiver class so that reading a corrupt archive returns nil (as though the file were not there) rather than throwing an exception, but I can't be certain whether any of those third-party frameworks might do things correctly (with an #try/#catch block) and might break in interesting ways if I do so.
It would be helpful if I could somehow examine the Objective-C exception handling tree (or equivalent) to determine whether an exception handler would catch an exception if thrown, and if so, which handler. That way, my patched method could return nil if the exception would make it all the way up to Crashlytics (which would rethrow it, causing a crash), but could rethrow the exception if some other handler would catch it.
Is such a thing possible, and if so, how?
Why not wrap your exception-throwing callsite in a try/catch/finally?
#try {
//call to your third party unarchiver
}
#catch {
//remove your corrupted archive
}
#finally {
//party
}
Rolling your own global exception handler may also be of use here, ala: How do you implement global iPhone Exception Handling?
If you're not sure that wrapping third-party library code with #try/#catch is good enough you can hook NSKeyedUnarchiver methods to replace them with exact same wrapper thus making sure that exception is never gets thrown outside. Here is pseudo-code:
#try {
//call original NSKeyedUnarchiver implementation
}
#catch {
return nil;
}
Objc runtime has public APIs that can do such a thing

Do not stop test execution on XCTAssertThrowsSpecific

Using XCTest, a test does the following:
XCTAssertThrowsSpecificNamed([does something that breaks], NSException, NSInvalidArgumentException);
I don't want the debugger to stop on the NSException that I know will occur but I want it to still stop on other exceptions that might occur.
Basically we don't have a choice. I still consider it an xCode bug because you already told xCode an exception will be thrown, and what exception it will be. Why provide XCTAssertThrows if it's an exception you're not "expecting"?
Obviously it's for exceptions you are expecting, which #nhgrif argues should be an error, not an exception. Might be a good point, but i do want my program to crash if this case ever happens, because I can't handle it.
So the real question is more why not disable the debugger on that exception only? Probably because they haven't gotten around to it. I'd suggest opening a bug/feature request with Apple. I'd love for someone to contradict me on this (please comment!) but until then, I'll live with this issue (disable debugger when running all my tests).
--> https://stackoverflow.com/a/22393643/1701430
"Why does the test stop when the execution is thrown?"
Because you have a breakpoint, which stops execution.
"Why, after removing the breakpoint, does my application crash when the exception is thrown?"
Because you have an unhandled exception. Unhandled exceptions cause your program to crash.
"How can I handle an exception so it won't crash my program?"
The easy answer to this question is to simply NOT throw an exception. In other programming languages, like Java, this is perfectly standard. But in Objective-C, we don't really do exceptions. In Objective-C, exceptions should be saved for TRULY exceptional behavior.
With that said, and a strong suggestion for you to find another way to handle whatever it is you're trying to handle, this is how you handle an exception in Objective-C:
#try {
// code that could throw an exception
}
#catch (NSException *e) {
// handle the exception...
}
#finally {
// post try-catch code, executed every time
}

Difference between try catch and NSSetUncaughtExceptionHandler

I have tried two methods for catching the exceptions. First one is with a try catch and the second one is with the following code in Appdelegate.
void onUncaughtException(NSException* exception)
{
//save exception details
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSSetUncaughtExceptionHandler(&onUncaughtException);
}
The advantage of the second method is we don need to implement try catch blocks in each and every method.
The first one catches the exception, prints it but does not crash the application.. But the second one catches the exception and crashes the application. Is there any way to use the second method to catch exceptions without crashing the application.
NSSetUncaughtExceptionHandler Sets the top-level error-handling function where you can perform last-minute logging before the program terminates. in the onUncaughtException you can do something before crash, but app do crash finally.
#try...#catch...#finally.. is to try to catch possible NSException, if catch, run in the #catch block code, no matter if catch, code will run in #finally block code. Using #try...#catch... will not cause crash finally, this may be the main difference.

Resources