2009-08-18 17 views
0

这是一个相当简单的例子,可能是没有多大的差别无论如何,但说我有一个鉴于这种绘图代码来绘制一个渐变:是否有必要在iPhone上缓存-drawRect的常用操作?

@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 

可以很明显的看到这里的权衡;特别是如果我有很多这样的观点的话,那么最终可能会用这种技术来获得更多的记忆,而前者的绘图表现可能更差。然而,我甚至不确定是否有很多折衷因为我不知道幕后的可可魔在做什么。谁能解释一下?

回答

1

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

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

+0

什么时候失效? – Michael 2009-08-18 21:26:10

+0

+1至于什么时候它失效了,很多事情都可以使它无效,并且可以使视图的一部分无效(这就是为什么-drawRect:传递给你一个CGRect来告诉你哪个部分失效了)。当然,您调用-setNeedsDisplay会使其失效。当视图出现在屏幕上时。当视图的“状态”改变时(例如突出显示)。当视图的大小发生变化时。有时在滚动期间(虽然有一些位图缓存优化)。 – 2009-08-18 21:36:10

+0

在进一步的评论中,Apple建议您不要自己绘制渐变,只要您能够帮助它。 iPhone并不总是足够快。苹果的建议是使用图像。渐变通常用单像素宽的图像处理,然后水平伸展以填充所需的区域。 – 2009-08-18 21:39:22

0

每个UIView都有其自己的屏外绘图缓冲区,因此移动围绕UIView或改变它的可见性将不会导致UIView被重绘。正如已经提到的那样,有些特定的实例会触发重绘,但只要不导致这些事件发生,就不应该调用drawRect例程。 (作为一个实验,尝试使用NSLog调用来启动drawRect例程,以观察它何时被调用。)通过限制绘制实际发生的次数,这将使您在绘制“快速”时更近一步。

您还应该能够使用Shark等性能测量工具来查看您的绘图程序花了多长时间,以及哪些花费最多时间。特别是,这种分析有助于避免缓存某些您认为可能会很昂贵的东西,但实际上并非如此,从而导致您在时间和复杂性方面表现很差。

相关问题