Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

MrFusion

macrumors 6502a
Original poster
Jun 8, 2005
613
0
West-Europe
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?
 
Can you post the code in your custom view?

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];
}
 
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.
 
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.

Thanks for the explanation

Other tests to try

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

Fail

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.

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.
 
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)?
 
This problem is beyond my current programming skills. Any advice is welcome.

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.
 
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.

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:
 
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 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.
 
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);	
}
 
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);	
}

Thanks !
 
This fact suggests you aren't implementing initWithCoder: correctly in PlotView, your custom NSView subclass.


Code:
- (id)initWithCoder:(NSCoder *)decoder

is never called in my NSView subclass.

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

That is what I meant.
 
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?

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?
 
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.
 
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"
 
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"

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.
 
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
}

Thanks. That does seems to be the recommend path. I will keep trying.

Alternatively if you only require 10.5 and up use the NSTrackingArea class with NSView's addTrackingArea: method.

If that method is better, I'll upgrade to it in my next version.
 
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:

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.

And this was your reply:

This is a new project, with the bare minimum of code/functionality. It doesn't really do anything, except crash in the same manner.

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.
 
Frankly, I can't think of anything other than uploading the entire project.

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).
 
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?
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.