views:

353

answers:

2

I am a complete newbie to XCode, so I have been climbing the Quartz2D learning curve. I understand that a view's drawRect method is called whenever a refresh of the view's graphics is needed, and that the setNeedsDisplay method activates a redrawing.

But what I can't find is a clear explanation of the relationship between the graphics context and a specific view. The graphics context itself is apparently not an instance variable of the view, so if I want to modify a view, and I create a complex path using the CGContext... methods, what code is needed to marry that graphics context to the view I wish to alter?

Thanks in advance for any guidance on this question.

jrdoner

+3  A: 

You don't create a graphics context. This is done for you. You just need to get the context by calling UIGraphicsGetCurrentContext().

When the framework determines that a view needs redrawing (for various reasons, one of which is that you indicated it by calling setNeedsDisplay:), it will generate (or restore) a graphics context for that view, and make it the current context before calling -drawRect:. Your job is then to draw in the context you've been provided. Afterwards, it is the framework's problem to clip the resulting context, blend it with other contexts and finally draw it into screen memory.

Do be a little careful of doing too much complex drawing in -drawRect: if you can help it. The iPhone doesn't have nearly as powerful a CPU as a desktop machine, and it is recommended that you do most of your drawing work using images rather than paths. Apple has even removed many of the more convenient drawing wrappers from Mac, almost intentionally dissuading developers from using Core Graphics too much.

Rob Napier
Great answer. Btw, what you say about doing complex drawing in drawRect: is is very interesting, and I'd like to read more. Do you know of any official Apple documentation (or any other discussion) on the subject of preferring the loading of images over programmatic drawing?
erikprice
To follow up, would writing programatically drawn content to a CGLayer (rather than redrawing repeatedly in drawRect: ) be an acceptable alternative to loading and manipulating images?
erikprice
Regarding Apple's recommendations, these are from my WWDC notes where they discussed why they wanted stretched images with end-caps versus gradients on buttons. There doesn't seem to be a "Drawing Performance Guidelines" for iPhone there way there is for Mac. While my notes are from 2008 sessions, I recommend WWDC 2009 Session #132 (iPhone Views and Animations) if you have access. Regarding GCLayer versus drawRect:, the point is that CGGradient and CGPath are CPU-expensive, which means battery-expensive. So we should avoid them when practical. They aren't forbidden of course :D
Rob Napier
A: 

I assume that you are creating your path within -(void)drawRect:(CGRect)rect method of your UIView subclass.

Inside drawRect you can get access to graphic context by calling (CGContextRef)UIGraphicsGetCurrentContext(void);

Example from lecture 5 cs193p:

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    [[UIColor grayColor] set];
    UIRectFill ([self bounds]);
    CGContextBeginPath (context);
    CGContextMoveToPoint (context, 75, 10);
    CGContextAddLineToPoint (context, 10, 150);
    CGContextAddLineToPoint (context, 160, 150);
    CGContextClosePath (context);
    [[UIColor redColor] setFill];
    [[UIColor blackColor] setStroke];
    CGContextDrawPath (context, kCGPathFillStroke);
}
stefanB