2012-06-25 3 views
3

Mac OS X 10.7에서 내 코코아 기반 응용 프로그램에 이상한 문제가 있음을 알았습니다. 몇 가지 이유로 (여기에 중요하지 않음) 때로는 사용자 정의보기의 drawRect 메서드 외부로 그려야합니다.display 대 setNeedsDisplay

나는 나는 또한 NSGraphicsContext을 창을 세척하거나 사용할 수 있습니다 (내보기에 lockFocus/lockFocusIfCanDraw를 호출 현재 컨텍스트를 요청, 기능의 CGContext 제품군 (CoreGrapchis)와 실제 도면을해야하고, 마지막에 CGContextFlush을 플러시를 수행하는 클래스 메서드).

이 시퀀스는 NSView의 -display 메소드를 호출 할 때와 실제로 동일합니다.

문제는 "자연적인"방법보다 3 ~ 4 배 느립니다 (setNeedsDisplay를 호출하거나 drawRect에서 코코아가 이것을 요구할 때 그리기). 보기에 setNeedsDisplay와 같이 단순히 호출 할 수는 없지만이 '-display-like'기능이 필요합니다.

테스트 예제 (타이머 사용)에서는 간단히하기 위해 -display를 호출합니다. (일반적으로 내 앱과 동일한 작업을 수행하므로) -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를 모두 시도 할 수 있습니다. 예를 들어 다음과 같은 출력이 있습니다.

-display : 3.32 초. (?)

-setNeedsDisplay : 1.2 초.

'Instruments'앱에서 제작 한 통화 트리/시간을 보았지만 그다지 도움이되지 못했습니다.

편집 : 흠, 이제 확인할 수 있습니다. 사실, setNeedsDisplay보기는 모든 타이머 이벤트에서 다시 그려지지 않습니다!

답변

0

drawRect 메소드의 CG 기능을 드롭 다운 할 필요가 없습니다.

이 코드는 동일하다 :

-display 및 -setNeedsDisplay로서는
- (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)); 
    } 
} 

는, 전자는 그 플래그가있는 경우, 도면이 이벤트 루프를 통해 즉시 후자 세트 플래그 및마다 발생하게 true이면 창은 문제의보기로 디스플레이를 보내고 플래그를 지 웁니다.

한 가지 더 : 애니메이션을 구동하기 위해 NSTimer를 사용하는 이러한 접근법은 약간 오래된 것입니다. 이런 종류의 작업을 수행하는 방법을 배우려면 Core Animation의 문서를 읽어야합니다.

+0

그래, setNeedsDisplay가 플래그를 설정하지만 나중에 AppKit (?)이이 플래그를 무시하고 뷰가 다시 그려지지 않을 수 있습니까? (타이머 이벤트의 2/3 정도) – user1479515

+0

내 애플 리케이션에서 코코아가 충분하지 않아 CoreGrapchis를 사용하고 있기 때문에 여기에 CoreGraphics 호출이 있습니다.여기서 NSTimer는 중요하지 않습니다. 실제 앱 타이머는 저와 다른 방식으로 구현되지 않습니다. 타이머 이벤트를 처리하는 사람조차도 아닙니다. NSTimer는 원시 애니메이션을 수행하고 표시 속도가 느리다는 것을 보여줍니다. – user1479515