how to soive this to stop warning message for this? am trying to put error on label. Does try catch really prevent crashing app?
#catch (NSException *ex) {
errorLbl.text =ex;
}
Instead of trying to catch a crash, you should make sure that code will not crash altogether. However, you can always convert the NSException to NSString
#catch (NSException *ex) {
errorLbl.text = [NSString stringWithFormat:#"%#",[ex reason]];
}
NSException
#interface NSException : NSObject <NSCopying, NSCoding> {
#private
NSString *name;
NSString *reason;
NSDictionary *userInfo;
id reserved;
}
This question is hard to understand, but if your asking, will that Catch catch every exception that is based off of a NSException, then the answer is yes, with a small issue.
You can catch it, but since your not doing anything about it, the code will continue after the catch. If your app is crashing, then what will happen is you will fill some label with the error, but it wont mean the app is in a stable position, it might just keep crashing.
NSException's reason contains a "human readable" reason that you could display, like:
#catch (NSException *ex) {
errorLbl.text = ex.reason;
}
See the NSException reference for more info.
It's worth noting that exceptions in Objective-C (unlike in other languages) are intended to be used for programming or unexpected runtime errors, not normal program flow. The docs state:
Important: 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.
For further information, see Error Handling Programming Guide.
See the Error Handling Programming Guide.
Related
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;
}
...
}
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.
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
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
}
I have a weird crash here that I believe is stemming from an external library, but I'm having trouble tracking down the stack trace, and not sure how to use Xcode's memory exploration tools.
This is what I'm getting in the console when it crashes:
*** Terminating app due to uncaught exception 'NSGenericException',
reason: '*** Collection <__NSArrayM: 0x208c5d00> was mutated while being enumerated.'
*** First throw call stack:
(0x37ae32a3 0x35e0d97f 0x37ae2d85 0x7c57d 0x728b1 0x6b865 0x34d9f11f 0x34d9e4b7 0x34da31bd 0x37ab6f3b 0x37a29ebd 0x37a29d49 0x368602eb 0x38ffb2f9 0x643d1 0x64358)
libc++abi.dylib: terminate called throwing an exception
I'm using MKNetworkKits UIImageView setImageFromURL additions to supply images to a UITableViewCell imageview (a custom imageview object, not the default imageview that comes with UITableViewCell). When I remove this setImageFromURL call, I don't get any crashes.
I tried using dwarfdump and atos on the command line but none of the addresses in the crash above link to any specific function addresses.
I have scoured for places where forin enumeration loops are being performed, but can't seem to find any that actually mutate data. Clearly I'm overlooking something..
Any advice/tips/help here would be super appreciated..
EDIT: Thanks so far for the comments. Any tips on how to utilize the memory address to trace down actual lines of codes would be helpful - can Xcode do some of what Visual Studio debugger can do, with respect to code & memory inspection?
Steps :
Run application and check on which ViewController the app is crashing with this exception.
Once you find the ViewController check entire code for that controller for NSArray.
Check related delegate you are calling from that controller, if any.
Check all custom subclasses you are using in that controller.
From the description it seems like you are enumerating an NSArray and checking values of it. Once you find the value you want to change those value. So, you are creating a mutableCopy of NSArray and trying to change inside the current running enumeration.
Solution :
Create NSMutableArray outside enumeration. While enumerating NSArray the objectAtIndex: will remain same for both array when you find the value you want to change. Change it inside mutable copy(created outside). [Bad for memory]
Create NSMutableArray outside enumeration of current NSArray. Then enumerate NSMutableArray. [Enumeration Will be Slower as you are enumerating mutable copy]
Hunt the Bug down!
This maybe useful for you:
replace your main.m file code with this (for ARC):
int main(int argc, char *argv[])
{
#autoreleasepool {
int retVal = -1;
#try {
retVal = UIApplicationMain(argc, argv, nil, NSStringFromClass([FRAppDelegate class]));
}
#catch (NSException* exception) {
NSLog(#"Uncaught exception: %#", exception.description);
NSLog(#"Stack trace: %#", [exception callStackSymbols]);
}
return retVal;
}
}
I suggest, starting simple, somewhere, you are altering an array, probably an NSMutableArray inside a loop. This can be easily fixed by using temporary store, them remove the temp objects AFTER the loop completes.
If this does not help, set an exception break point to break on all exceptions. This will likely stop on the line of code causing the error.
This helped:
https://stackoverflow.com/a/12266856/420594
Editing the Debug scheme and switching from LLDB to GDB helped a great deal - the crash points directly to a line of my own code now.