views:

357

answers:

3

Hello,

EDIT: Issue has been solved(partially):It is a simulator bug. I've compiled and tested this on two devices with iOS 3.1.3 and 4.0. The exception was handled correctly. Be careful, the simulator is your enemy!

this is driving me crazy. I don't know how to enable exception handling in my project. Look at the code and debugger output below.

My Goal is to catch the exception, not correcting the code so the exception is handled and the app doesn't crash.

I'm using XCode 3.2.3, iPhone SDK 4 final. I have just created a simple view based iPhone App to test this.

I have looked in my project settings and yes the switch "Enable Objective-C Exceptions" is checked. I am using GCC 4.2.

When I look at the build process in detail the compiler flag -fno-objc-exceptions is not within the list of arguments!

What am I missing here?

Thanks in advance Nick

NSArray * foo = [[NSArray alloc] init];

@try {
   NSLog(@"trying...");  
   [foo objectForKey:@"yeah"];
}
@catch (NSException * e) {
   NSLog(@"catching %@ reason %@", [e name], [e reason]);
}
@finally {
   NSLog(@"finally");
}

leads to

trying...

-[__NSArrayI objectForKey:]: unrecognized selector sent to instance 0x5d5f780

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI objectForKey:]: unrecognized selector sent to instance 0x5d5f780'

*** Call stack at first throw:
(
 0   CoreFoundation                      0x02393919 __exceptionPreprocess + 185
 1   libobjc.A.dylib                     0x024e15de objc_exception_throw + 47
 2   CoreFoundation                      0x0239542b -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
 3   CoreFoundation                      0x02305116 ___forwarding___ + 966
 4   CoreFoundation                      0x02304cd2 _CF_forwarding_prep_0 + 50
...
)
terminate called after throwing an instance of 'NSException'

Whether the catch nor the finally block is ever reached.

A: 

If I understand your problem right.

Your Try/ catch block is working correctly.

It is trying to run your code, and catches an error. You need to decide what to do when it catches an error and code for it within the block. I normally do that in the CATCH part. As the finally bit will execute regardless of an exception or not being thrown.

markhunte
The example code is just a simple scenario to force an exception which should be caught.
Nick Weaver
I THINK because your NSArray is empty, you will not see an error, because nil is always returned.
markhunte
try This, NSArray * foo = [NSArray arrayWithObjects:@"yeah", @"yeah1", nil];Instead of NSArray * foo = [[NSArray alloc] init];
markhunte
You're getting it wrong. I want this exception as it is. It's not about handling NSArray. It's about handling exception which are thrown if you send a message to an object which it doesn't recognize.
Nick Weaver
Yes after I posted my answer, I realised you are trying to force an error, when I ran you code the first time, I did not get any error returned?. I do now, which means I did something odd!.I am admittedly confused by what you expect to happen.
markhunte
I am expecting to run into the catch block, which it doesn't: the app crashes with "terminate called after throwing an instance of 'NSException'".
Nick Weaver
Ah, I see from you update what you mean. Even though your TRY/CATCH block should work. It does not for you, but does for me.I have never had to setup enable Objective-C Exceptions. It was enabled when I first ever ran Xcode.My return is ::a0f] trying...:a0f] -[__NSArray0 objectForKey:]: unrecognized selector sent to instance 0x100111380a0f] catching NSInvalidArgumentException reason -[__NSArray0 objectForKey:]: unrecognized selector sent to instance 0x100111380a0f] finally
markhunte
Ok thanks. The problem is my coworker has the same issue so I posted this here. Which XCode and SDK are you using, markhunte? Can anyone else confirm, that this is working for him/her?
Nick Weaver
Xcode : Version 3.2.1 , SDK 10.6
markhunte
And just did it on iphone SDK 3.1.2
markhunte
+1  A: 

Quote from http://stackoverflow.com/questions/2826351/how-do-i-catch-global-exceptions : "objc_exception_throw is not an exception. It is the function that throws Objective-C exceptions. Similarly, EXC_ARITHMETIC is not an Objective-C exception; it is a Mach (kernel) exception, meaning that your app tried to do something completely invalid. – Peter Hosey May 14 at 9:14"

That thread does have a link to a solution for your problem though, it appears. The link goes to http://www.restoroot.com/Blog/2008/10/20/crash-reporter-for-iphone-applications-part-2/ which looks a little risky, but if it works, it might be worth it for you.

There are bug reports related to this, e.g.: http://www.openradar.me/8081169 (posted earlier this month)

(Updated to summarize information from comments below.)

Kalle
Thanks for the post I am looking into it.
Nick Weaver
What I do not understand is: there is an exception in this case: NSInvalidArgumentException which is stated as not caught and it is an instance of NSException. So it seems there are some kind of exception which cannot be caught. Sending an unknown message to an instance of an object is something which should be a common case in such a dynamic language like objective-c, so how to handle such an exception?
Nick Weaver
That's a good point. Have you looked into `NSSetUncaughtExceptionHandler`? E.g. http://stackoverflow.com/questions/1282364/iphone-exception-handling
Kalle
Yes I did. Apple documentation says on this "Sets the top-level error-handling function where you can perform last-minute logging before the program terminates." The app should not terminate :)
Nick Weaver
This might be a bug: http://www.openradar.me/8081169
Kalle
Thanks Kalle, it does look like a bug. A bit sad actually.
Nick Weaver
A: 

Your example code is catching the NSException exception but not the one being thrown, NSInvalidArgumentException. You might have better luck if you look for that specific exception.

NSArray * foo = [[NSArray alloc] init];

@try {
   NSLog(@"trying...");  
   [foo objectForKey:@"yeah"];
}
@catch (NSInvalidArgumentException *e) {
   NSLog(@"Invalid argument called.");
}
@catch (NSException * e) {
   NSLog(@"catching %@ reason %@", [e name], [e reason]);
}
@finally {
   NSLog(@"finally");
}

I don't have any way of testing it myself right now, though.

See http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocExceptionHandling.html for more information.

jsumners
This won't compile as NSInvalidArgumentException is defined as string constants which is no NSException class or a class inheriting fromNSException.
Nick Weaver
Looks like the reference to http://www.openradar.me/8081169 is accurate. I imagine this exception would be handled by NSException but it's currently bugged.
jsumners
Yes, I am accepting that.
Nick Weaver