MyNSView invalid context

Discussion in 'Mac Programming' started by MrFusion, Sep 15, 2009.

  1. MrFusion macrumors 6502a

    Joined:
    Jun 8, 2005
    Location:
    West-Europe
    #1
    Hello

    I have a strange bug. My document has a subclass of NSView in which I do custom drawing. I can open multiple documents and the drawing is all fine.
    However, when I close the first document (and only the first document) that was created during that session, I get a bunch of errors. These errors occur when drawing in the other windows.

    Code:
    ....
    <Error>: CGContextAddCurveToPoint: invalid context
    <Error>: CGContextAddCurveToPoint: invalid context
    <Error>: CGContextAddCurveToPoint: invalid context
    <Error>: CGContextAddCurveToPoint: invalid context
    <Error>: CGContextDrawPath: invalid context
    <Error>: CGContextRestoreGState: invalid context
    
    Any idea why this would be happening? Why would the context only be valid when the first document is around?
     
  2. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
  3. MrFusion thread starter macrumors 6502a

    Joined:
    Jun 8, 2005
    Location:
    West-Europe
    #3
    It's too much code (~700 lines) to post here, but this part is where I do something with the context.

    Code:
    -(void) plot {
    	//ask datasource for plot function or plot data
    	NSArray *plots = [datasource plots];
    	NSPoint xyValue, xyPoint;
    	
    	//clip plotarea
    	[NSGraphicsContext saveGraphicsState];
    	NSBezierPath *clip = [NSBezierPath bezierPathWithRect:plotArea];
    	[clip addClip];
    	
    	//go through the plots
    	int i,j,nbrOfPoints=0;
    	for (i=0; i<[plots count]; i++) {
    		NSBezierPath *path = [NSBezierPath bezierPath];
    		NSDictionary *dt = [plots objectAtIndex:i];
    		if ([[dt valueForKey:@"showPlot"] boolValue]){
    			switch ([[dt valueForKey:@"typeOfPlot"] intValue]) {
    				case ...:
    ...
    Do actual drawing
    ...
    					break;
    				default:
    					printf("Unknown plottype %i",[[dt valueForKey:@"typeOfPlot"] intValue]);
    					break;
    			}
    		}
    		//draw path
    		[[dt valueForKey:@"color"] set];
    		[path stroke];
    	}
    	
    	//undo clipping
    	[NSGraphicsContext restoreGraphicsState];
    }
    
     
  4. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #4
    The symptoms sound like you have an accidental singleton (a shared instance of some object). It's created when the first document is opened. Subsequent documents share it, because it already exists (first document still open). Closing the first document then releases or removes the accidental singleton, and all subsequent documents have then lost their context.

    Other tests to try

    Open 1st document, close it. Open 2nd document. Does it work or fail?

    If 2nd document works, open 3rd document, close 2nd. Does 3rd still work?

    These are to test when or where the accidental singleton might be getting created (or not created). You could also probably find it by setting breakpoints on plot that are conditional on 1st document vs. others.
     
  5. MrFusion thread starter macrumors 6502a

    Joined:
    Jun 8, 2005
    Location:
    West-Europe
    #5
    Thanks for the explanation

    Fail

    As far as I can tell, there are no shared or static instances related to the NSView.
    I do have an NSObject instance (MyController) in the nib file, which is a mediator between the data and the MyView.

    Just doing nothing already gives a problem

    Code:
    - (void)drawRect:(NSRect)rect { 
       return;
    }
    
    When the NSView is delete from the nib file, there is no problem.

    This problem is beyond my current programming skills. Any advice is welcome.
     
  6. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #6
    I've seen that error before and I'm pretty sure it was a result of human error in terms of using the APIs. However, I believe when I encountered it it was not from using AppKit classes but the direct CG functions.

    From the original post it looks like you're drawing a curve. Can you post any code that might be doing that (e.g. rounded rect)?
     
  7. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #7
    My advice is to post your code, in a form that someone else can compile and debug it. Anything less is just fumbling around in the dark.

    You don't have to post your code here. You can upload it to somewhere like pastebin.com and then post the URL here. Any number of other free upload services would also work. Google keywords: free upload service.
     
  8. MrFusion thread starter macrumors 6502a

    Joined:
    Jun 8, 2005
    Location:
    West-Europe
    #8
    This is a new project, with the bare minimum of code/functionality. It doesn't really do anything, except crash in the same manner.

    Feel free to comment on any aspects of this code. I might learn something from it. I don't think it is good enough to be widely used, so please don't distribute it. It does what I need it to do, and that is good enough for me. :)
    Well, except for that annoying crashing feature. :mad:
     
  9. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #9
    This fact suggests you aren't implementing initWithCoder: correctly in PlotView, your custom NSView subclass.

    http://developer.apple.com/mac/libr...ls/NSCoding_Protocol/Reference/Reference.html

    I'm assuming your statement "When the NSView is delete..." refers to your PlotView instance, and not some other NSView instance.

    If a do-nothing drawRect fails, it suggests the problem may not be with the invocation of drawRect, but somewhere else.
     
  10. lloyddean macrumors 6502a

    Joined:
    May 10, 2009
    Location:
    Des Moines, WA
    #10
    Code:
    -(NSPoint) startPoint:(int) index forPlot:(NSNumber *) plotID{
    	int plot = [plotID intValue];
    	if (plot = 0)	// accidental assignment, should be comparison
    		return NSMakePoint([[self valueForKey:@"xMin"] floatValue],0); //horizontal line
    	if (plot = 1)	// accidental assignment, should be comparison
    		return NSMakePoint(0,[[self valueForKey:@"yMin"] floatValue]); //vertical line
    	return NSMakePoint(0,0);	
    }
    -(NSPoint) endPoint:(int) index forPlot:(NSNumber *) plotID{
    	int id = [plotID intValue];
    	if (id = 0)	// accidental assignment, should be comparison
    		return NSMakePoint([[self valueForKey:@"xMax"] floatValue],0); //horizontal line
    	if (id = 1)	// accidental assignment, should be comparison
    		return NSMakePoint(0,[[self valueForKey:@"yMax"] floatValue]); //vertical line
    	return NSMakePoint(0,0);	
    }
    
     
  11. MrFusion thread starter macrumors 6502a

    Joined:
    Jun 8, 2005
    Location:
    West-Europe
    #11
    Thanks !
     
  12. MrFusion thread starter macrumors 6502a

    Joined:
    Jun 8, 2005
    Location:
    West-Europe
    #12

    Code:
    - (id)initWithCoder:(NSCoder *)decoder 
    
    is never called in my NSView subclass.

    That is what I meant.
     
  13. MrFusion thread starter macrumors 6502a

    Joined:
    Jun 8, 2005
    Location:
    West-Europe
    #13
    I had another look at this old bug.
    The problem is not with the "initWithCoder" as Chown33 suggested. I don't save anything from the classes involved in this bug.
    But I did find out that the problem is due to these lines of code.
    Code:
      	trackingTag = [self addTrackingRect:plotArea
    								 owner:self
    							  userData:nil
    						  assumeInside:mouseIsInsidePlotArea];
    
    It seems that my app is sending events to a no longer existing object, because I seemingly can't get rid of the tracking rectangle.
    Adding
    Code:
    [self removeTrackingRect:trackingTag];
    
    to dealloc does not work.

    I find it still strange that the error would occur only after the first document is removed.

    So how do I get rid of the tracking rectangle?
     
  14. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #14
    I'd remove and add it when the view is added to a window. You can override the NSView method viewDidMoveToWindow and do something like this:

    Code:
    - (void)viewDidMoveToWindow
    {
        if ([self window])
            // view was added to a window. add tracking rect
        else
            // view was removed from a window. remove tracking rect
    }
    Alternatively if you only require 10.5 and up use the NSTrackingArea class with NSView's addTrackingArea: method.
     
  15. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #15
    dealloc is the wrong place.

    How to find the right place.

    1. I entered the following search terms in google:

    cocoa addTrackingRect: class reference

    2. The top hit is:

    Mac Dev Center: Cocoa Event-Handling Guide: Mouse-Tracking and ...

    3. On that page, find:

    remov

    (about 15 matches)

    4. On that page, find:

    removing

    "Listing A-4 Removing a tracking rectangle when a view is removed from its window"
     
  16. MrFusion thread starter macrumors 6502a

    Joined:
    Jun 8, 2005
    Location:
    West-Europe
    #16
    Or go to cocoadev, and type in "addTrackingRect". cocoadev has an interesting discussion about the difficulties to remove the tracking rectangle.
    However, nothing I found works for me. I could list several things I tried, or just ask directly. After moving and copying code around and trying different things, my entire subclass is a mess of non-working, semi-comprehensible code. So, I chose the latter and see what the suggestions here might be. Oh, there were no prior discussions on "addTrackingRect" on this forum, except for 1 thread which I answered.

    Yes, I know how to use google and the internet. And no, it doesn't always give an answer.
     
  17. MrFusion thread starter macrumors 6502a

    Joined:
    Jun 8, 2005
    Location:
    West-Europe
    #17
    Thanks. That does seems to be the recommend path. I will keep trying.

    If that method is better, I'll upgrade to it in my next version.
     
  18. MrFusion thread starter macrumors 6502a

    Joined:
    Jun 8, 2005
    Location:
    West-Europe
    #18

    Eureka!
    There were two bugs, both causing a similar problem. One related to the tracking rectangle and one with regard to drawing.
    Thanks everyone.
     
  19. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #19
    First, if you don't list the things you've tried, how would we know what you've tried? The one thing you posted was in dealloc. How would anyone know that you'd also read the class reference, read cocoadev, and tried everything they'd suggested without success unless you tell us?

    Second, if you'd actually gone to the page that I pointed you at, using the procedure I'd posted, you would see it describes viewDidMoveToWindow: to remove tracking rects. If you'd already tried that without success, how would we know unless you tell us?

    Now, if it turns out that viewDidMoveToWindow doesn't work for you, then I recommend following the advice I made on 18 Sep:

    And this was your reply:

    However, you still haven't provided a complete context for debugging the problem, so we're still just fumbling around in the dark. We can only guess what your complete code looks like. We can only guess what's in the nibs. Guessing at these things is not an effective debugging strategy.

    A complete context includes the nibs as well as the code, because one small change to a nib can have a huge effect on what happens when that nib is loaded and used.

    As you've also already stated, this problem is beyond your debugging skills.

    So if you're the only one with the code and the nibs, but you admit lacking the skills to debug it, what procedure do you think is most likely to let someone with greater skills actually debug the project? Frankly, I can't think of anything other than uploading the entire project.
     
  20. MrFusion thread starter macrumors 6502a

    Joined:
    Jun 8, 2005
    Location:
    West-Europe
    #20
    The relevant code was online for several weeks until today. It is the same project I was fumbling around with today. The problem was within that code. The problem is fixed (for as far as I can tell).
     
  21. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #21
    Where was the code online? I don't see a compilable class anywhere.

    If you mean the extracts and isolated methods you posted in this thread, that's not the same as a complete compilable subclass of NSView. Since the problem turned out to be a method that you hadn't implemented, how is anyone supposed to know that without seeing the entire class defined, and then deducing that you hadn't implemented an important method?
     

Share This Page