2012-06-25 57 views
3

我注意到我的基於Cocoa的應用程序在Mac OS X 10.7上出現了一個奇怪的問題。 由於某種原因(這裏不重要),有時我必須繪製自定義視圖的drawRect方法以外的內容。我需要在我的視圖中調用lockFocus/lockFocusIfCanDraw,請求當前上下文,使用CGContext系列函數(CoreGrapchis)做實際繪圖,並在最後執行CGContextFlush(我也可以刷新窗口,或者使用NSGraphicsContext類方法做一個刷新)。display vs setNeedsDisplay

這個序列實際上和我調用NSView的顯示方法一樣。

問題是......它比「自然」方式慢3-4倍(當Cocoa要求你這樣做時,調用setNeedsDisplay或從drawRect中繪製)。 我不能簡單地調用setNeedsDisplay作爲視圖,我需要這個''類似'的功能。

在一個測試示例中(使用定時器),爲了簡單起見,我調用了-display(因爲它通常執行與我的應用程序相同的工作)vs -setNeedsDisplay,我可以看到'-display '比'setNeedsDisplay'長3-4倍。

這裏是我的CustomView類(實現)的例子:

#import <QuartzCore/QuartzCore.h> 

#import "CustomView.h" 

@implementation CustomView 
{ 
    CFTimeInterval startTime; 
    NSTimer *timer; 
    unsigned step; 
} 

- (id)initWithFrame:(NSRect)frame 
{ 
    return [super initWithFrame : frame]; 
} 

- (void)drawRect:(NSRect)dirtyRect 
{ 
    CGContextRef ctx = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; 

    if(!timer) 
    { 
     CGContextSetRGBFillColor(ctx, 1., 1., 1., 1.); 
     CGContextFillRect(ctx, dirtyRect); 
    } 
    else 
    { 
     CGContextSetRGBFillColor(ctx, 0., 0., 0., 1.); 
     CGContextFillRect(ctx, CGRectMake(step * 1.5, 100, 2., 2.)); 
    } 
} 

- (void) mouseDown : (NSEvent *)theEvent 
{ 
    if (!timer) 
    { 
     startTime = CACurrentMediaTime(); 
     timer = [NSTimer scheduledTimerWithTimeInterval : 0.006 target : self selector : @selector(handleTimer:) userInfo : nil repeats : YES]; 
     step = 0; 
    } 
} 

- (void) handleTimer : (NSTimer *) dummy 
{ 
    if(step < 200) 
    { 
     ++step; 
#if 1 
     [self display]; 
#else 
     [self setNeedsDisplay : YES]; 
#endif 
    } 
    else 
    { 
     [timer invalidate]; 
     timer = nil; 
     NSLog(@"animation time is: %g", CACurrentMediaTime() - startTime); 
    } 
} 

@end 

我想就算CACurrentMediaTime不是我的目的確實不錯的功能,但它仍然可以顯示出明顯的時間差(這很容易通知沒有任何測量 - 顯示真的很慢)。 handleTimer方法有兩個部分 - 如果您在pp-directive中將'1'更改爲'0',則可以嘗試使用-display/-setNeedsDisplay。所以,我有,例如下面的輸出:

- 顯示:3.32秒。 (?)

-setNeedsDisplay:1.2 s。

我看過由'Instruments'應用程序製作的調用樹/時間,但它對我沒有多大幫助。

編輯: 嗯,我現在可以看到:實際上,setNeedsDisplay視圖不會在每個計時器事件上重新繪製!

回答

0

在drawRect方法中不需要下拉到CG函數。

這段代碼是等價的:

- (void)drawRect:(NSRect)dirtyRect 
{ 
    if(!timer) 
    { 
     [[NSColor whiteColor] set]; 
     NSRectFill(dirtyRect); 
    } 
    else 
    { 
     [[NSColor blackColor] set]; 
     NSRectFill(NSMakeRect(step * 1.5, 100.0, 2.0, 2.0)); 
    } 
} 

至於-display和-setNeedsDisplay,前者使得繪圖通過事件循環立即發生,後者設置一個標誌,每一次,如果該標誌是如果爲true,該窗口將發送 - 顯示到有問題的視圖並清除標誌。

還有一件事:這種使用NSTimer驅動動畫的方法有點過時。你應該閱讀Core Animation上的文檔來學習如何做這種事情。

+0

好吧,所以setNeedsDisplay設置標誌,但後來AppKit(?)可以忽略這個標誌並且視圖不會被重繪? (大約在計時器事件的2/3中) – user1479515

+0

我有一個CoreGraphics調用,因爲在我的應用程序中Cocoa對我來說還不夠,我正在使用CoreGrapchis。NSTimer在這裏並不重要,在我的真實應用中,定時器不是由我實現的,而是以不同的方式處理定時器事件,即使我不處理定時器事件,NSTimer在這裏只做原始「動畫」,並用-display顯示它很慢。 – user1479515