Avoid crash report when a code snippet in CodeRunner throws exception - objective-c

When using CodeRunner to test Objective-C code snippets, any exception thrown during run time will cause a crash, followed by the <my program> quit unexpectedly alert with complete stack trace and crash report saved in ~/Library/Logs/DiagnosticReports.
The exception can for instance be the result of a misspelled method name, and can happen quite often, depending on your personal development style. It is worth noticing that this crash report is also sent to Apple, which can seem a bit excessive for a misspelled method name.
Can this alert and crash report be avoided?

The default code template can be changed for each programming language in the app's Preferences settings.
If a try-catch block is added, the snippet can catch all its own exceptions and for instance just print out a log statement, hence avoiding the crash report.
For Objective-C, it can look like this:
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
#autoreleasepool {
#try {
%#
} #catch (NSException *e) {
NSLog(#"Exception caught: %#", e);
}
}
}
The %# defines the initial insertion point when a new file is opened.

Related

Throwing custom exception from completionhandler/block crashes the app in objective c

I am trying to throw exception from my custom framework. It works well if it is thrown outside block.
But app crashes on [exception raise] if its within block.
How to create a completion handler/block with throws in objective C.
typedef void (^ServerResponse) (id responseObject, BOOL requestSuccess, NSError* error);
- (void)getData:(NSUInteger*)id response:(ServerResponse)response
{
NSString* url = [NSString stringWithFormat:#"%#data/%#“,ServerUrl,[NSString stringWithFormat:#"%ld",(long)vid]];
…………..
………
if(statuscode == 200 && [response objectForKey:#“something”])
{
NSException* exception = [NSException exceptionWithName:#“Name” reason:#“Data id" userInfo:nil];
[exception raise];
}
}
The problem is likely that your block is getting called asynchronously. Thus, you have probably already exited your #try-#catch block by the time the exception is raised. You can confirm this by adding a #finally clause that logs some message, and you'll probably see it called before the exception is raised. But if the block is called synchronously, the exception will be successfully caught by the #catch block.
As an aside, if you want to report an error in a routine, you should pass NSError objects, not throw exceptions like you might in other languages. Exceptions are for programming errors you excise in the development phase, not to be used for control flow for situations that may arise naturally during routine use of the app.
See the Exception Programming Topics, which says:
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.

Objective-C EXC_BAD_ACCESS on run

I'm creating a basic command line application using this tutorial: http://www.raywenderlich.com/40293/learn-to-code-ios-apps-2-strings-arrays-objects-and-classes
I'm at the stage where it is asks me to type in:
NSLog(#"You entered the word '%#' and it is %li characters long", inputString, [inputString length]);
When I do that, run the app and type in a word in the console window it says I should get
Please enter a word.
objects
You entered the word 'objects' and it is 7 characters long
Which does happen, but then the screen automatically switches to:
the error on the green bar says:
Thread 1: EXC_BAD_ACCESS (code=13, address=0x0)
Can someone explain this?
Run the Zombies instrument in Instruments. The crash is caused by releasing an invalid "object". Probably this is because the object was over-released. The Zombies instrument will tell you more about over-release problems.
There's nothing wrong with that line of code.
What's likely happening is that you have nothing after that line of code, and those lines you typed in need to live between the brackets in this template:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
#autoreleasepool {
// your code goes HERE
}
return 0;
}

Xcode debugger can't catch exception if finally block returns

I discovered weird behavior of Xcode.
Xcode debugger doesn't break for uncaught exception in this code.
#try { #throw #"AA"; }
#catch (...) { #throw; }
#finally { return; }
But exception in this code caught and trigger Xcode break execution for debugging.
#try { #throw #"AA"; }
#catch (...) { #throw; }
#finally { }
If #finally block returns debugger can't catch the exception. Have you ever seen this problem? I'm not sure this is really an issue. By the perspective it looks like designed behavior. I don't know why. Shouldn't I return in #finally block? My problem is it swallows exception silently, so I can't detect it.
Shame on me, I don't know well try...catch...finally behaviors. I almost haven't used exception catching code. Is this designed behavior or buggy behavior? Is this any known issue?
Here's my environment.
Xcode Version 4.4 (4F250)
OS X 10.7.4
Edit
I attach full test source code.
#import <Foundation/Foundation.h>
int main (int a, char** b)
{
#try
{
NSLog(#"trying something...");
#try { #throw #"AA"; }
#catch (...) { #throw; }
#finally { return 0; }
}
#catch (...)
{
NSLog(#"something catched.");
}
#finally
{
NSLog(#"finally...");
}
}
Putting a return in a #finally block seems like a bad idea. The exception handling mechanism is going to try to unwind the call stack as it deals with the exception you're throwing. If a #finally block changes what's on the stack, you undermine the exception handler. It doesn't seem at all surprising that this crashes.
Also, as bbum pointed out, exceptions aren't used for flow control in Cocoa and Cocoa Touch. Throwing an exception through a Cocoa method usually fails. Even if what you're doing is supposed to work in generic Objective-C, it would probably still cause problems in real code.
Short answer: Don't do that.

Fail to catch exception from proxy object under Xcode 3.2.3

I use HessianKit to communicate with server. In the situation of network or server down Hessian will throw exception, so I put every Hessian call in a #try ... #catch block. Everything worked fine until I upgraded Xcode from 3.2.2 to 3.2.3. I wrote the some testing code and found under Xcode 3.2.3, catch exception would be failed if the exception was thrown from a proxy object.
MyProxy.h:
#interface MyProxy : NSProxy {
}
#end
MyProxy.m:
#implementation MyProxy
- (id)init {
return self;
}
- (void)forwardInvocation:(NSInvocation *)invocation {
NSLog(#"Call method %#", NSStringFromSelector([invocation selector]));
[NSException raise:#"MyException" format:#"this is an exception"];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
.....
}
#end
Code using MyProxy:
#try {
MyProxy *p = [[MyProxy alloc] init];
[p doSomething];
[p release];
}
#catch (NSException * e) {
NSLog(#"%#", e);
}
When these code build under xcode 3.2.2, the exception can be catched correctly. But under xcode 3.2.3, the program terminated after output following on the console:
2010-09-08 21:09:29.877 BriefCase[34651:40b] Call method doSomgthing
2010-09-08 21:09:29.879 BriefCase[34651:40b] *** Terminating app due to uncaught exception 'MyException', reason: 'this is an exception'
2010-09-08 21:09:29.880 BriefCase[34651:40b] Stack: (
45955152,
47113004,
45692683,
45692522,
151932,
45426420,
45423090,
9352,
4417860,
4421967,
4447550,
4429047,
4461016,
53399932,
45234332,
45230248,
4420129,
4453234,
8812,
8666
)
terminate called after throwing an instance of 'NSException'
Program received signal: “SIGABRT”.
What can I do?
I filed a bug with Apple, and the reply is:
It has been determined that this is a known issue, which is currently being investigated by engineering. This issue has been filed in our bug database under the original Bug ID# 7995323.
Maybe your project/target/executable settings have been messed up?
Is the "Enable Objective-C Exceptions" box ticked for your configuration/target/etc?
If it is, maybe you should file a bug with Apple here.

throwing an exception in objective-c/cocoa

What's the best way to throw an exception in objective-c/cocoa?
I use [NSException raise:format:] as follows:
[NSException raise:#"Invalid foo value" format:#"foo of %d is invalid", foo];
A word of caution here. In Objective-C, unlike many similar languages, you generally should try to avoid using exceptions for common error situations that may occur in normal operation.
Apple's documentation for Obj-C 2.0 states the following: "Important: Exceptions are resource-intensive in Objective-C. You should not use exceptions for general flow-control, or simply to signify errors (such as a file not being accessible)"
Apple's conceptual Exception handling documentation explains the same, but with more words: "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."
The reasons for this is partly to adhere to programming idioms in Objective-C (using return values in simple cases and by-reference parameters (often the NSError class) in more complex cases), partly that throwing and catching exceptions is much more expensive and finally (and perpaps most importantly) that Objective-C exceptions are a thin wrapper around C's setjmp() and longjmp() functions, essentially messing up your careful memory handling, see this explanation.
#throw([NSException exceptionWith…])
Xcode recognizes #throw statements as function exit points, like return statements. Using the #throw syntax avoids erroneous "Control may reach end of non-void function" warnings that you may get from [NSException raise:…].
Also, #throw can be used to throw objects that are not of class NSException.
Regarding [NSException raise:format:]. For those coming from a Java background, you will recall that Java distinguishes between Exception and RuntimeException. Exception is a checked exception, and RuntimeException is unchecked. In particular, Java suggests using checked exceptions for "normal error conditions" and unchecked exceptions for "runtime errors caused by a programmer error." It seems that Objective-C exceptions should be used in the same places you would use an unchecked exception, and error code return values or NSError values are preferred in places where you would use a checked exception.
I think to be consistant it's nicer to use #throw with your own class that extends NSException. Then you use the same notations for try catch finally:
#try {
.....
}
#catch{
...
}
#finally{
...
}
Apple explains here how to throw and handle exceptions:
Catching Exceptions
Throwing Exceptions
Since ObjC 2.0, Objective-C exceptions are no longer a wrapper for C's setjmp() longjmp(), and are compatible with C++ exception, the #try is "free of charge", but throwing and catching exceptions is way more expensive.
Anyway, assertions (using NSAssert and NSCAssert macro family) throw NSException, and that sane to use them as Ries states.
Use NSError to communicate failures rather than exceptions.
Quick points about NSError:
NSError allows for C style error codes (integers) to clearly identify the root cause and hopefully allow the error handler to overcome the error. You can wrap error codes from C libraries like SQLite in NSError instances very easily.
NSError also has the benefit of being an object and offers a way to describe the error in more detail with its userInfo dictionary member.
But best of all, NSError CANNOT be thrown so it encourages a more proactive approach to error handling, in contrast to other languages which simply throw the hot potato further and further up the call stack at which point it can only be reported to the user and not handled in any meaningful way (not if you believe in following OOP's biggest tenet of information hiding that is).
Reference Link: Reference
This is how I learned it from "The Big Nerd Ranch Guide (4th edition)":
#throw [NSException exceptionWithName:#"Something is not right exception"
reason:#"Can't perform this operation because of this or that"
userInfo:nil];
You can use two methods for raising exception in the try catch block
#throw[NSException exceptionWithName];
or the second method
NSException e;
[e raise];
I believe you should never use Exceptions to control normal program flow. But exceptions should be thrown whenever some value doesn't match a desired value.
For example if some function accepts a value, and that value is never allowed to be nil, then it's fine to trow an exception rather then trying to do something 'smart'...
Ries
You should only throw exceptions if you find yourself in a situation that indicates a programming error, and want to stop the application from running. Therefore, the best way to throw exceptions is using the NSAssert and NSParameterAssert macros, and making sure that NS_BLOCK_ASSERTIONS is not defined.
Sample code for case: #throw([NSException exceptionWithName:...
- (void)parseError:(NSError *)error
completionBlock:(void (^)(NSString *error))completionBlock {
NSString *resultString = [NSString new];
#try {
NSData *errorData = [NSData dataWithData:error.userInfo[#"SomeKeyForData"]];
if(!errorData.bytes) {
#throw([NSException exceptionWithName:#"<Set Yours exc. name: > Test Exc" reason:#"<Describe reason: > Doesn't contain data" userInfo:nil]);
}
NSDictionary *dictFromData = [NSJSONSerialization JSONObjectWithData:errorData
options:NSJSONReadingAllowFragments
error:&error];
resultString = dictFromData[#"someKey"];
...
} #catch (NSException *exception) {
  NSLog( #"Caught Exception Name: %#", exception.name);
  NSLog( #"Caught Exception Reason: %#", exception.reason );
resultString = exception.reason;
} #finally {
completionBlock(resultString);
}
}
Using:
[self parseError:error completionBlock:^(NSString *error) {
NSLog(#"%#", error);
}];
Another more advanced use-case:
- (void)parseError:(NSError *)error completionBlock:(void (^)(NSString *error))completionBlock {
NSString *resultString = [NSString new];
NSException* customNilException = [NSException exceptionWithName:#"NilException"
reason:#"object is nil"
userInfo:nil];
NSException* customNotNumberException = [NSException exceptionWithName:#"NotNumberException"
reason:#"object is not a NSNumber"
userInfo:nil];
#try {
NSData *errorData = [NSData dataWithData:error.userInfo[#"SomeKeyForData"]];
if(!errorData.bytes) {
#throw([NSException exceptionWithName:#"<Set Yours exc. name: > Test Exc" reason:#"<Describe reason: > Doesn't contain data" userInfo:nil]);
}
NSDictionary *dictFromData = [NSJSONSerialization JSONObjectWithData:errorData
options:NSJSONReadingAllowFragments
error:&error];
NSArray * array = dictFromData[#"someArrayKey"];
for (NSInteger i=0; i < array.count; i++) {
id resultString = array[i];
if (![resultString isKindOfClass:NSNumber.class]) {
[customNotNumberException raise]; // <====== HERE is just the same as: #throw customNotNumberException;
break;
} else if (!resultString){
#throw customNilException; // <======
break;
}
}
} #catch (SomeCustomException * sce) {
// most specific type
// handle exception ce
//...
} #catch (CustomException * ce) {
// most specific type
// handle exception ce
//...
} #catch (NSException *exception) {
// less specific type
// do whatever recovery is necessary at his level
//...
// rethrow the exception so it's handled at a higher level
#throw (SomeCustomException * customException);
} #finally {
// perform tasks necessary whether exception occurred or not
}
}
There is no reason not to use exceptions normally in objective C even to signify business rule exceptions. Apple can say use NSError who cares. Obj C has been around a long time and at one time ALL C++ documentation said the same thing. The reason it doesnt matter how expensive throwing and catching an exception is, is the lifetime of an exception is exceedingly short and...its an EXCEPTION to the normal flow. I have never heard anyone say ever in my life, man that exception took a long time to be thrown and caught.
Also, there are people that think that objective C itself is too expensive and code in C or C++ instead. So saying always use NSError is ill-informed and paranoid.
But the question of this thread hasnt yet been answered whats the BEST way to throw an exception. The ways to return NSError are obvious.
So is it: [NSException raise:... #throw [[NSException alloc] initWithName....
or #throw [[MyCustomException... ?
I use the checked/unchecked rule here slightly differently than above.
The real difference between the (using the java metaphor here) checked/unchecked is important --> whether you can recover from the exception. And by recover I mean not just NOT crash.
So I use custom exception classes with #throw for recoverable exceptions, because
its likely I will have some app method looking for certain types of failures in multiple
#catch blocks. For example if my app is an ATM machine, I would have a #catch block for the
"WithdrawalRequestExceedsBalanceException".
I use NSException:raise for runtime exceptions since I have no way to recover from the exception,
except to catch it at a higher level and log it. And theres no point in creating a custom class for that.
Anyway thats what I do, but if there's a better, similarly expressive way I would like to know as well. In my own code, since I stopped coding C a hella long time ago I never return an NSError even if I am passed one by an API.