Difference between try catch and NSSetUncaughtExceptionHandler - ios

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.

Related

Uncaught exception in appdelegate swift 3

How do I handle all unhandled exceptions in application level?
I tried with NSSetUncaughtExceptionHandler and it called only for NSExceptions.
I would like to handle uncaught exceptions in app level and allow users to continue with app without any crashes by navigating to home (some)page.
I recommend you to use try catch block in your code. It will help to prevent the crashes in your application.
do {
try {
// do something here
// if the call fails, the catch block is executed
}
} catch {
//do something when catch block executes.
}

Objective-C - how to do exception catch and avoid to have app crash?

When i call this function few times from my button (like mad more then few times), then my app crash instead of just throw exception and ignore.
How do you ignore to crash when exception happened?
where localView is UIView *localView.
- (void)smallLocalView {
#try {
self.localView.backgroundColor = [UIColor blackColor];
[self.localView.layer removeFromSuperlayer];
//self.localView.opaque = NO;
}
#catch(NSException *exp) {
//NSLog(#">>> failed %#" , exp.reason);
NSLog(#"OK - but dont crash!!!");
}
#finally {
NSLog(#"OK - but dont crash!!!");
}
}
EDIT:
tl;dr In general you shouldn't try to catch exceptions, you should try to fix the root cause.
There are two kinds of exception you are interested in. The first kind as shown in your image is a system exception. The processor has encountered a problem, for example trying to access protected memory (usually called by trying to dereference a null pointer). You cannot catch that kind of an exception. The operating system will terminate your program when one is raised.
The problem, by the way, is almost certainly caused by localView having been deallocated prematurely, or maybe you access it not on the main thread (as per Edgar's answer).
The other kind of exception is the Objective-C exception which is always raised programmatically. Although you can catch these with a #try { ... } #catch { ... } block, in general you should not. The reason is that there is no enforcement to make code exception safe, so the exception may unwind stack frames where resources need to be deallocated or stack frames where clean up is needed to keep data structures consistent. Once an exception is thrown and caught, you cannot guarantee the logical consistency of your program's state. Your only real option is to terminate as cleanly as possible.
Make sure you are on the Main thread when changing the background color.
You can add an assert at the beginning, like this, other check the stack trace on the left side when you get the exception in order to check in which thread you're on:
NSAssert([NSThread isMainThread]);
Also, depending on where you are calling smallLocalView from, it might happen that your view is not loaded/ready.
- (void)smallLocalView {
if (!self.isViewLoaded) {
return;
}
...
}

Throwing an exception from anywhere in project

I want to show alert whenever an exception occured anywhere in my code.
Without enclosing the code that may throw exception.
Everytime when exception occures it shows error in main class. Is that possible to handle from there?
This is normal way of throwing an exception im using:
#try {
// code that may throw exception
}
#catch (NSException * e) {
// show alert
}
#finally {
}
However, I have found an effective work-around - creating my own exception handler (which is also useful for other reasons). First, create a function that will handle the error and output it to the console (as well as whatever else you want to do with it)
void uncaughtExceptionHandler(NSException *exception) {
NSLog(#"CRASH: %#", exception);
NSLog(#"Stack Trace: %#", [exception callStackSymbols]);
// Internal error reporting
}
Next, add the exception handler to your app delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
// Normal launch stuff
}
If this doesn't work, then there are only two possible reasons:
Something is overwriting your NSSetUncaughtExceptionHandler call (there can be only one handler for your entire app). For example, some 3rd party libraries set their own uncaughtExceptionHandler. So, try setting it at the END of your didFinishLaunchingWithOptions function (or selectively disabling 3rd party libraries). Or better yet, set a symbolic break point on NSSetUncaughtExceptionHandler to quickly see who is calling it. What you may want to do is to modify your current one rather than adding another one.
You're not actually encountering an exception (for example, EXC_BAD_ACCESS is not an exception)
Navigate to Breakpoint panel in Xcode, click "plus" button at the left-bottom to add a new breakpoint, then do this:
build and run your project, Xcode will brings you to the line where exception throws.
If I'm understanding the question correctly, it seems that you're looking for a good way to handle errors in your code that may have been driven by a user action (e.g. invalid data, missing fields in a form, etc.).
The best way to do this would be to use NSError instead of NSException. NSError is generally used to pass information between different code interfaces that are expecting a possible error, where as NSException is more so for errors that are unexpected, or caused by the developer and thus, should be handled during development.
To present an alert from anywhere in your code, you could add a method to your App Delegate and use target-action to pass along your error. That might look like this:
#protocol DLErrorPresentation <NSObject>
- (void)showAlertWithError:(NSError*)error sender:(id)sender
#end
- (void)showAlertWithError:(NSError*)error sender:(id)sender {
// Your alert presentation code
}
// In some view controller or view:
NSError* error;
if(![self somethingThatMayError:error]) {
id<DLErrorPresentation> responder = [self targetForAction:#selector(showAlertWithError:sender:);
[responder showAlertWithError:error sender:self]
}
To provide additional context, here's what Apple says about exceptions in their documentation:
You should reserve the use of exceptions for programming or unexpected runtime errors such as out-of-bounds collection access, attempts to mutate immutable objects, sending an invalid message, and losing the connection to the window server. You usually take care of these sorts of errors with exceptions when an application is being created rather than at runtime.
Instead of exceptions, error objects (NSError) and the Cocoa error-delivery mechanism are the recommended way to communicate expected errors in Cocoa applications.
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Exceptions/Exceptions.html#//apple_ref/doc/uid/10000012i
Although exceptions are commonly used in many programming environments to control programming flow or to signify errors, do not use exceptions in this way in Cocoa and Cocoa Touch applications. Instead, you should use the return value of a method or function to indicate that an error has occurred, and provide information about the problem in an error object.
https://developer.apple.com/library/content/documentation/General/Conceptual/DevPedia-CocoaCore/ExceptionHandling.html#//apple_ref/doc/uid/TP40008195-CH18-SW1
I have added exception handling code inside my main.m.
int main(int argc, char * argv[]) {
#try {
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFrom
Class([AppDelegate class]));
}
} #catch (NSException *exception) {
NSLog(#"exception");
}
}
Its working now.

catch exceptions in iOS main Runloop

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

Is there any method in appDelegate which is called when application crashes?

I need to save some data in my application, when the application terminates and even if it crashes. I know that applicationWillTerminate is called when application terminates but I am not sure which method is called when application crashes.
Can someone help me here?
Well you could add your own exception handler, to catch the error.
First you need to define the exception method:
void uncaughtExceptionHandler(NSException *exception) {
// You code here, you app will already be unload so you can only see what went wrong.
}
Then tell the app to use your exception handler:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
// The rest if you code ....
}
There is no way to make the app save data on crashing, since saving could be the reason for the crash!
No, you cannot get to know when the application crashes.

Resources