2013-03-09 104 views
1

我正在用NSTimer每隔0.1秒從網格中繪製單元格。 大小約爲96x64 => 6144個細胞/圖像。 如果我正在繪製圖像而不是(例如)綠色矩形,它會慢4倍!改善drawRect的性能:

- (void)drawRect:(CGRect)rect 
{ 
    CGContextRef context = UIGraphicsGetCurrentContext(); 
    UIGraphicsPushContext(context); 
    CGContextSetRGBFillColor(context, 0, 0, 0, 1); 
    CGContextFillRect(context, CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height)); 
    int cellSize = self.bounds.size.width/WIDTH; 
    double xOffset = 0; 
    for (int i = 0; i < WIDTH;i++) 
    { 
     for (int j = 0; j < HEIGHT;j++) 
     {     
       NSNumber *currentCell = [self.state.board objectAtIndex:(i*HEIGHT)+j]; 
       if (currentCell.intValue == 1) 
       { 
        [image1 drawAtPoint:CGPointMake(xOffset + (cellSize * i),cellSize * j)]; 
       } 
       else if (currentCell.intValue == 0){ 
        [image2 drawAtPoint:CGPointMake(xOffset + (cellSize * i),cellSize * j)]; 
       } 
     } 
    } 
    UIGraphicsPopContext(); 
} 

任何想法如何使這更快,如果我想在每個矩形中繪製PNG或JPG格式? 圖像已經縮放到合適的尺寸。

+0

圖像是否實際調整了圖像文件大小,還是隻是在內存中縮放? – 2013-03-09 16:10:48

+0

它們現在只在內存中縮放。我試圖縮放沒有任何結果的文件(很驚訝)!變化是從64×64像素到10×10像素... – Shamino 2013-03-09 16:38:03

+1

有很多方法可以改善代碼的性能,例如,將'CGPointMake'中的乘法轉換爲加法,使'self.levelState.board'成爲C數組而不是'NSArray'。但是,這裏的瓶頸並不是檢查重新粉刷的區域,而是每0.1秒鐘重新繪製就顯得有點奇怪。只有遊戲需要重繪,這就是爲什麼我們有OpenGL ... – Sulthan 2013-03-09 17:02:23

回答

3
  • a)不要重繪超出視圖邊界的圖像/矩形。

  • B)不要重繪圖像/ rects屬於dirtyRect

  • C溫度範圍之外)不要重繪圖像/ rects有自 以前的更新不會改變。

  • d)使用圖層預渲染圖像,因此您不需要在繪製時渲染它們 。

+0

a)檢查b)檢查c)我如何保留舊的圖形上下文/確保只添加新的矩形並保留舊的圖形? d)這是否像緩衝區一樣工作?它是異步的嗎? – Shamino 2013-03-09 16:41:36

+0

現在我相信c)和d)只有在解決在一起時纔可能,因爲我在當前的圖形環境中繪製..我試過的任何其他東西導致中間有空/灰色的口袋...... – Shamino 2013-03-09 19:39:41

+0

UIImage * currentContext = [self drawCurrentContext ]。 [currentContext drawInRect:self.bounds];試圖沒有結果...仍然灰色中間...在考慮之後,我認爲我做對了,但調用drawCurrentContext到後期... – Shamino 2013-03-09 19:54:37

0

使用CGRectIntersects來檢查您的圖像的矩形是否在dirtyRect中,以檢查是否需要繪製它。

1

我試圖從性能角度改進您的代碼。不過,請查看我對瓶頸的評論。

- (void)drawRect:(CGRect)rect { 
    CGContextRef context = UIGraphicsGetCurrentContext(); 
    //UIGraphicsPushContext(context); //not needed UIView does it anyway 

    //use [UIView backgroundColor] instead of this 
    //CGContextSetRGBFillColor(context, 0, 0, 0, 1); 
    //CGContextFillRect(context, CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height)); 

    int cellSize = self.bounds.size.width/WIDTH; 
    double xOffset = 0; 

    CGRect cellFrame = CGRectMake(0, 0, cellSize, cellSize); 
    NSUinteger cellIndex = 0; 

    for (int i = 0; i < WIDTH; i++) { 
     cellFrame.origin.x = xOffset; 

     for (int j = 0; j < HEIGHT; j++, cellIndex++) {     
      cellFrame.origin.y = 0; 

      if (CGRectIntersectsRect(rect, cellFrame) { 
       NSNumber *currentCell = [self.state.board objectAtIndex:cellIndex]; 

       if (currentCell.intValue == 1) { 
        [image1 drawInRect:cellFrame]; 
       } 
       else if (currentCell.intValue == 0) { 
        [image2 drawInRect:cellFrame]; 
       } 
      } 

      cellFrame.origin.y += cellSize; 
     } 

     cellFrame.origin.x += cellSize; 
    } 

    //UIGraphicsPopContext(context); //not needed UIView does it anyway 
} 
+0

執行上述代碼後,有一個約10-20幀每分鐘(而不是秒)的加速....我將使用它除了上述,所以非常感謝你..我不能給這個答案一個好評因爲我是新的,如果任何人都可以請這樣做... – Shamino 2013-03-09 19:09:16

2

這種場景正是儀器所在的地方。用它。任何人在這裏提出建議都是猜測瓶頸是什麼。

這就是說,我要猜測瓶頸是什麼。您正在使用CPU繪製6114圖像(使用時間分析器確認此問題,找到您的drawRect方法,並檢查大部分時間花在哪裏,如果是drawInRect,那就是您的問題)

如果是這種情況,我們是否減少使用量?簡單的勝利是隻重繪我們需要繪製的圖像。 CALayers使這很簡單。刪除drawRect方法,爲每個圖像的視圖圖層添加一個子圖層,並將圖像設置爲圖層的內容屬性。當圖像需要更改時,不要使視圖無效,只需將相關圖層的內容屬性切換到新圖像即可。

CALayers的另一個好處是他們可以在GPU上緩存圖層內容,這意味着重繪所發生的重繪將需要更少的CPU時間,並且不會在應用程序發生時阻止其他應用程序。

如果許多圖層的開銷是不可接受的(同樣,Instruments是你的朋友),請檢查CAReplicatorLayer。它比具有許多CALayer的靈活性更低,但可以以最小的開銷多次複製單個圖像。

+0

是的,它也關於該方法..將嘗試CALayers ... – Shamino 2013-03-10 09:25:05

+0

爲此問題打開新線程:http://stackoverflow.com/questions/15315619 /如何對平局對上下文沒有預虧,它/ 15322628#15322628 – Shamino 2013-03-10 13:17:04