是否有必要在iPhone上缓存-drawRect的常用操作?

时间:2009-08-18 21:09:17

标签: iphone objective-c cocoa-touch optimization

这是一个相当简单的例子,无论如何可能不会产生太大的影响,但是说我在绘制渐变的视图中有这个绘图代码:

@interface SomeView : UIView
@end

@implementation SomeView

- (void)drawRect:(CGRect)rect
{
    const CGContextRef ctx = UIGraphicsGetCurrentContext();

    // Set fill color to white
    CGContextSetGrayFillColor(ctx, 1.0f, 1.0f);
    CGContextFillRect(ctx, rect);

    // Create a fancy, albeit ugly, orange gradient
    const CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
    const CGFloat components[] = { 1.0, 0.5, 0.4, 1.0,   // Start color
                                   0.8, 0.8, 0.3, 1.0 }; // End color
    CGGradientRef gloss;
    gloss = CGGradientCreateWithColorComponents(rgbColorSpace, components, NULL, 2);
    CGColorSpaceRelease(rgbColorSpace);

    // Draw the gradient
    const CGPoint endPoint = {rect.origin.x,
                              rect.origin.y + floor(rect.size.height / 2.0f)};
    CGContextDrawLinearGradient(ctx, gloss, rect.origin, endPoint, 0);
    CGGradientRelease(gloss);
}

@end

我意识到这是一个非常微不足道的例子,但是如果我有更复杂的值可以重用,你可以想象出这个问题。是否有必要缓存这些内容,或者Cocoa-Touch基本上是否通过CALayers为您执行此操作?

以下是缓存的含义示例:

@interface SomeView : UIView
{
    CGGradientRef gloss;
}
@end

@implementation SomeView

- (id)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        // Create a fancy, albeit ugly, orange gradient only once here instead
        const CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
        const CGFloat components[] = { 1.0, 0.5, 0.4, 1.0,   // Start color
                                       0.8, 0.8, 0.3, 1.0 }; // End color
        CGGradientRef gloss;
        gloss = CGGradientCreateWithColorComponents(rgbColorSpace, components, NULL, 2);
        CGColorSpaceRelease(rgbColorSpace);
    }
    return self;
}

- (void)dealloc
{
    CGGradientRelease(gradient);
    [super dealloc];
}

- (void)drawRect:(CGRect)
{
    const CGContextRef ctx = UIGraphicsGetCurrentContext();

    // Set fill color to white
    CGContextSetGrayFillColor(ctx, 1.0f, 1.0f);
    CGContextFillRect(ctx, rect);

    // Draw the gradient
    const CGPoint endPoint = {rect.origin.x,
                              rect.origin.y + floor(rect.size.height / 2.0f)};
    CGContextDrawLinearGradient(ctx, gloss, rect.origin, endPoint, 0);
}

@end

你可以在这里看到权衡;特别是如果我有很多这样的观点,它可能最终会用这种技术占用更多的内存,而前者的绘图性能可能更差。但是,我甚至不确定是否需要进行权衡,因为我不知道Cocoa在幕后做了什么。谁能解释一下?

2 个答案:

答案 0 :(得分:1)

唯一“缓存”是drawRect:消息的结果。它被缓存直到无效,在这种情况下,再次调用该消息。

Cocoa和Cocoa-Touch不会缓存您在方法中使用的对象。您可以自己缓存它们,就像在第二个示例中所做的那样。但是,我建议使用诸如Instruments之类的分析器来测试这样的优化,以确保您不会因为代码过于复杂而没有太多的好处。

答案 1 :(得分:0)

每个UIView都有自己的屏幕外绘图缓冲区,因此移动UIView或改变其可见性不会导致UIView被重绘。如前所述,有一些特定的实例会触发重绘,但只要不引起重绘,就不应该调用drawRect例程。 (作为一个实验,尝试使用NSLog调用启动drawRect例程,以便在调用它时进行监视。)通过限制绘图实际发生的次数,这将使您更快地进行“快速”绘图。

您还应该能够使用像Shark这样的性能测量工具来查看您的绘图程序所花费的时间,以及花费最多时间的内容。特别是这种分析有助于防止缓存某些您认为可能非常昂贵的东西,但实际上并非如此,导致您在极少的性能上花费时间和复杂性。