Re: Dealing with exceptions in a drawing stack
Re: Dealing with exceptions in a drawing stack
- Subject: Re: Dealing with exceptions in a drawing stack
- From: Graham Cox <email@hidden>
- Date: Mon, 19 Jan 2009 22:07:15 +1100
On 19 Jan 2009, at 6:49 pm, Kyle Sluder wrote:
Well it sounds like there are a number of issues here:
1) You're throwing exceptions in drawing code. Even if you catch them
so they don't screw up the draw stack, this will be extremely slow and
have adverse effects on the drawing.
My understanding is that @try is pretty cheap, whereas the @catch is
not. Since these exceptions are very rare, the @catch block is not
being called routinely, so I'm hoping that it won't impact performance
(which is currently swamped by Core Graphics rendering times anyway).
2) You've gotten yourself into a situation in which you're trying to
meaningfully recover from an exception but you have to do it from a
place with outside of the exception's local context. This is why
Cocoa doesn't use exceptions for general circumstance; they're
notoriously hard to gracefully recover from.
Well, if it means I have to try/catch at every point that I save/
restore the graphics context, so be it, that's what I'll have to do.
But I was hoping I could catch it at some top level and "put things
right" without this approach being necessary.
Cocoa exceptions are not supposed to be reached in shipped code (which
I'm sure you are aware). It also sounds like the view state is a
critical component of your app's model. This sounds like a Very Bad
Idea(TM).
On further investigation, it seems that the majority of the "bad
state" is caused by the clipping path being set progressively smaller
as the drawing stack goes deeper. As you can probably visualise, that
isn't unusual. It means though that if an exception occurs the
clipping path may be very small when drawRect: returns. On the face of
it I can't see why that should matter - (the clipping path should be
mine to do with much as I please with drawRect: as long as I always
use addClip rather than setClip), in practice this screws up my
scrollbars and rulers in the enclosing NSScrollView. That in turn must
be because the scrollview is assuming that the contained view's
drawRect: will balance all save/restores of the graphics state.
If it's possible to recover from the exception, have you considered
just fixing the situation, obliterating the graphics context, and
redrawing the view? Perhaps calling -[NSView renewGState] will make
your view usable again.
I hadn't tried renewGState but I have now and it doesn't help. Since
the gState is always renewed when the view is focused prior to
drawing, that doesn't surprise me. The effects of the unbalanced
context stack are felt when exiting drawRect:, not entering it.
What does appear to help a lot is saving the current context at the
top of the drawing stack and putting it back explicitly at the end (as
per my previously posted code snippet). If the save/restores are
balanced, effectively this is a no-op, as I'm putting back the same
context that I saved. If an exception occurred, the save/restores are
unbalanced, and this code forces it to balance - thus, the
NSScrollView is no longer badly screwed up and things can progress
almost normally.
My question is, is this in any way legal?
In other words, the call stack looks like this:
@try
{
save graphics state
save graphics state
save graphics state
save graphics state
// normally draw stuff, but may throw an exception
restore graphics state
restore graphics state
restore graphics state
restore graphics state
}
@catch
{
// if there was an exception, the context stack is unbalanced - how
to rebalance it in a legal way before exiting?
}
--Graham
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden