iOS: Using UIView's 'drawRect:' vs. its layer's delegate 'drawLayer:inContext:'
How to decide which approach to use? Is there a use case for each one?
Always use drawRect:
, and never use a UIView
as the drawing delegate for any CALayer
.
how come the delegate method is called if my instance is not defined to be the layer's delegate? and what mechanism prevents drawRect from being called if
drawLayer:inContext:
is called?
Every UIView
instance is the drawing delegate for its backing CALayer
. That's why [[self layer] setDelegate:self];
seemed to do nothing. It's redundant. The drawRect:
method is effectively the drawing delegate method for the view's layer. Internally, UIView
implements drawLayer:inContext:
where it does some of its own stuff and then calls drawRect:
. You can see it in the debugger:
This is why drawRect:
was never called when you implemented drawLayer:inContext:
. It's also why you should never implement any of the CALayer
drawing delegate methods in a custom UIView
subclass. You should also never make any view the drawing delegate for another layer. That will cause all sorts of wackiness.
If you are implementing drawLayer:inContext:
because you need to access the CGContextRef
, you can get that from inside of your drawRect:
by calling UIGraphicsGetCurrentContext()
.
drawRect
should only be implemented when absolutely needed. The default implementation of drawRect
includes a number of smart optimizations, like intelligently caching the view's rendering. Overriding it circumvents all of those optimizations. That's bad. Using the layer drawing methods effectively will almost always outperform a custom drawRect
. Apple uses a UIView
as the delegate for a CALayer
often - in fact, every UIView is the delegate of it's layer. You can see how to customize the layer drawing inside a UIView in several Apple samples including (at this time) ZoomingPDFViewer.
While the use of drawRect
is common, it's a practice that has been discouraged since at least 2002/2003, IIRC. There aren't many good reasons left to go down that path.
Advanced Performance Optimization on iPhone OS (slide 15)
Core Animation Essentials
Understanding UIKit Rendering
Technical Q&A QA1708: Improving Image Drawing Performance on iOS
View Programming Guide: Optimizing View Drawing
Here're codes of Sample ZoomingPDFViewer from Apple:
-(void)drawRect:(CGRect)r
{
// UIView uses the existence of -drawRect: to determine if it should allow its CALayer
// to be invalidated, which would then lead to the layer creating a backing store and
// -drawLayer:inContext: being called.
// By implementing an empty -drawRect: method, we allow UIKit to continue to implement
// this logic, while doing our real drawing work inside of -drawLayer:inContext:
}
-(void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context
{
...
}