(Edit: is not just happening when screen is being touched. It seems to happen if the program has not recently started. Will keep investigating, but please respond with your ideas. May be related to this problem).
My iPhone project won't do anything with NSExceptions when the screen is being touched when it's been running for a few seconds.
When it has just started, it's fine. If (for example) I cause an exception in my code here:
NSException *e = [NSException
exceptionWithName:@"Testing"
reason:@"Testing exception handling"
userInfo:nil];
@throw e;
if (touched) {
}
...then the exception works as expected. If I've used NSSetUncaughtExceptionHandler then my &uncaughtExceptionHandler gets called; if I haven't, I get SIGABRT and the program terminates. All good.
But if I replace that with the following code (where touched is true if there's just been a touchesBegan):
if (touched) {
NSException *e = [NSException
exceptionWithName:@"Testing"
reason:@"Testing exception handling"
userInfo:nil];
@throw e;
}
...then the my NSSetUncaughtExceptionHandler code isn't called, and no SIGABRT signal is received. It seems to just stop performing that run loop & start the next one.
If you set a breakpoint there and do 'step over' or 'step into', then it just starts running as if you'd hit continue (but without running the remainder of that run loop).
The same thing happens in different classes. I have no try/catches that could be hijacking the NSException. It behaves the same way if I do something like...
[[NSArray array] objectAtIndex:1];
...to do the exception. It happens the same in both the simulator and the device.
Please help the exceptions get the recognition they deserve!
In response to bbum, here is the backtrace for the 1st case above, where the exception works as expected:
(gdb) BT
#0 -[Hud paintHudWithController:] (self=0x6475ee0, _cmd=0xbeb61, controller=0x686ac00) at /Users/mike/iPhone Dev/Parsec/Classes/Hud.m:2804
#1 0x00004f8e in -[ES1Renderer(Artist) paint] (self=0xa108a90, _cmd=0xc1b48) at /Users/mike/iPhone Dev/Parsec/Classes/ES1Renderer+Artist.m:92
#2 0x00003c22 in -[ES1Renderer render] (self=0xa108a90, _cmd=0x5f0dbb9) at /Users/mike/iPhone Dev/Parsec/Classes/ES1Renderer.m:81
#3 0x00003476 in -[EAGLView drawView:] (self=0xa103a70, _cmd=0xbe451, sender=0x64068a0) at /Users/mike/iPhone Dev/Parsec/Classes/EAGLView.m:79
#4 0x00c3c6a8 in CA::Display::DisplayLink::dispatch ()
#5 0x00c3c7ed in CA::Display::EmulatorDisplayLink::callback ()
#6 0x01494fe3 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ ()
#7 0x01496594 in __CFRunLoopDoTimer ()
#8 0x013f2cc9 in __CFRunLoopRun ()
#9 0x013f2240 in CFRunLoopRunSpecific ()
#10 0x013f2161 in CFRunLoopRunInMode ()
#11 0x000089e7 in -[Ticker tick] (self=0x686ac00, _cmd=0xbeb83) at /Users/mike/iPhone Dev/Parsec/Ticker.m:87
#12 0x00004e99 in -[ES1Renderer(Artist) paint] (self=0xa108a90, _cmd=0xc1b48) at /Users/mike/iPhone Dev/Parsec/Classes/ES1Renderer+Artist.m:67
#13 0x00003c22 in -[ES1Renderer render] (self=0xa108a90, _cmd=0x5f0dbb9) at /Users/mike/iPhone Dev/Parsec/Classes/ES1Renderer.m:81
#14 0x00003476 in -[EAGLView drawView:] (self=0xa103a70, _cmd=0xbe451, sender=0x0) at /Users/mike/iPhone Dev/Parsec/Classes/EAGLView.m:79
#15 0x000034ec in -[EAGLView layoutSubviews] (self=0xa103a70, _cmd=0x81b3de) at /Users/mike/iPhone Dev/Parsec/Classes/EAGLView.m:85
#16 0x00b80451 in -[CALayer layoutSublayers] ()
#17 0x00b8017c in CALayerLayoutIfNeeded ()
#18 0x00b7937c in CA::Context::commit_transaction ()
#19 0x00b790d0 in CA::Transaction::commit ()
#20 0x00ba97d5 in CA::Transaction::observer_callback ()
#21 0x01494fbb in __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ ()
#22 0x0142a0e7 in __CFRunLoopDoObservers ()
#23 0x013f2bd7 in __CFRunLoopRun ()
#24 0x013f2240 in CFRunLoopRunSpecific ()
#25 0x013f2161 in CFRunLoopRunInMode ()
#26 0x01de8268 in GSEventRunModal ()
#27 0x01de832d in GSEventRun ()
#28 0x0041e42e in UIApplicationMain ()
#29 0x000024a4 in main (argc=1, argv=0xbffff040) at /Users/mike/iPhone Dev/Parsec/main.m:13
and here is the backtrace for the 2nd case above, where the exception is apparently eaten:
(gdb) BT
#0 -[Hud paintHudWithController:] (self=0x6469710, _cmd=0xbeb61, controller=0x6855000) at /Users/mike/iPhone Dev/Parsec/Classes/Hud.m:2806
#1 0x00004a36 in -[ES1Renderer(Artist) paint] (self=0x7922720, _cmd=0xc1b48) at /Users/mike/iPhone Dev/Parsec/Classes/ES1Renderer+Artist.m:92
#2 0x000036ca in -[ES1Renderer render] (self=0x7922720, _cmd=0x5f0dbb9) at /Users/mike/iPhone Dev/Parsec/Classes/ES1Renderer.m:81
#3 0x00002f1e in -[EAGLView drawView:] (self=0x7907de0, _cmd=0xbe451, sender=0x7926cd0) at /Users/mike/iPhone Dev/Parsec/Classes/EAGLView.m:79
#4 0x00c3c6a8 in CA::Display::DisplayLink::dispatch ()
#5 0x00c3c7ed in CA::Display::EmulatorDisplayLink::callback ()
#6 0x01494fe3 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ ()
#7 0x01496594 in __CFRunLoopDoTimer ()
#8 0x013f2cc9 in __CFRunLoopRun ()
#9 0x013f2240 in CFRunLoopRunSpecific ()
#10 0x013f2161 in CFRunLoopRunInMode ()
#11 0x01de8268 in GSEventRunModal ()
#12 0x01de832d in GSEventRun ()
#13 0x0041e42e in UIApplicationMain ()
#14 0x00001f4c in main (argc=1, argv=0xbffff040) at /Users/mike/iPhone Dev/Parsec/main.m:13
I encountered the same thing in an OpenGL project a few weeks ago. It's because the display link installs a top-level exception handler. No way to get around this unfortunately, except to install your OWN mid-level exception handler in your display link handler and doing an abort () there if you catch an exception.
Worked for me, at least.
addendum: just discovered Core Animation also installs a top-level exception handler. Check for "CoreAnimation: ignoring exception" in your logs.
More likely than not, the exception is being eaten by whatever modal event loop is tracking the touch. File a bug via http://bugreporter.apple.com/.
In general, exceptions should never be used for control flow in iOS. Exceptions are to be treated as unrecoverable errors.
Which is why this is a bug; as you have correctly surmised the exception should kill the app.
Owerride a application method reportExceptions @implementation MyApplication
-(void) reportExceptions (NSException *)e
{
@try {
// show u expression here, [e callStackTrace] [e reason].
}
@catch (NSExpression *)ee {
// u can be wrong in try also :-).
}
}
Don't forget a setting custom application subclass in plist Principal Class =MyApplication
This may not be a solution but may help in finding one. There are 2 parts to my answer:
1) Try this to see if it makes any difference at all.
NSException *e = [NSException
exceptionWithName:@"Testing"
reason:@"Testing exception handling"
userInfo:nil];
if (touched) {
@throw e;
}
The only difference I see between the 2 code fragments you have, except for the fact that you need to throw the exception inside the if
statement, is that the NSException
is declared inside the if
.
2) Have you tried this to check if the exception can be caught at all when it is thrown inside the if
?
@try {
if (touched) {
NSException *e = [NSException
exceptionWithName:@"Testing"
reason:@"Testing exception handling"
userInfo:nil];
@throw e;
}
}
@catch (id anException) {
NSLog(@"Exception: %@", [anException description]);
}
Or try this to see if it works differently than the code above.
if (touched) {
@try {
NSException *e = [NSException
exceptionWithName:@"Testing"
reason:@"Testing exception handling"
userInfo:nil];
@throw e;
}
@catch (id anException) {
NSLog(@"Exception: %@", [anException description]);
}
}
Please let me know if you find anything interesting (like the 2 code fragments of part 2 working differently). It will help me as I learn about exceptions and how to catch them. Eventually, I have to create a crash reporter for the project I'm working on.
please try force retaining your views. [view retain]
User contributions licensed under CC BY-SA 3.0