I have a UITableView where I am trying to get the best possible scrolling performance.
The cell does not contain any subviews, all is done in the drawRect method.
Each cell has a white line at the top, a grey line at the bottom and a linear gradient between top and bottom. On top of this background is some text and an image.
I can see from using instruments that the main portion (>50%) of the runtime when scrolling comes from the drawing of the linear gradient. Actually almost all of that comes from the call to CGContextDrawLinearGradient.
Is there a good way to optimize this? I am thinking, either cache the linear gradient some way, or maybe draw it in another way… Maybe draw a one pixel wide and then stretch it?
Here is some of my code:
- (void)drawRect:(CGRect)rect
{
[self drawCellBackground:rect];
[self drawSeparator:rect];
....
}
- (void)drawCellBackground:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGColorRef notQuiteWhiteColor = [UIColor colorWithRed:245.0/255.0 green:245.0/255.0
blue:245.0/255.0 alpha:1.0].CGColor;
CGColorRef lightGrayColor = [UIColor colorWithRed:235.0/255.0 green:235.0/255.0
blue:235.0/255.0 alpha:1.0].CGColor;
drawLinearGradient(context, rect, notQuiteWhiteColor, lightGrayColor);
}
From a separate .c file:
void drawLinearGradient(CGContextRef context, CGRect rect, CGColorRef startColor, CGColorRef endColor)
{
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat locations[] = { 0.0, 1.0 };
NSArray *colors = [NSArray arrayWithObjects:(id)startColor, (id)endColor, nil];
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace,
(CFArrayRef) colors, locations);
CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect));
CGContextSaveGState(context);
CGContextAddRect(context, rect);
CGContextClip(context);
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
CGContextRestoreGState(context);
CGGradientRelease(gradient);
CGColorSpaceRelease(colorSpace);
}
If you absolutely want to stick to using drawRect: (which I believe gives better performance than separate views on older devices), why not prerender your gradient into a CGImage or UIImage, then use that to draw in -drawRect: ?
Also, you can create your gradient ahead of time:
For high performance code you want to preallocate as many things (memory/objects) as possible.