2009-08-18 59 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等性能測量工具來查看您的繪圖程序花了多長時間,以及哪些花費最多時間。特別是,這種分析有助於避免緩存某些您認爲可能會很昂貴的東西,但實際上並非如此,從而導致您在時間和複雜性方面表現很差。

相關問題