Mac OS X 10.7 上の Cocoa ベースのアプリケーションに奇妙な問題があることに気付きました。何らかの理由で (ここでは重要ではありません)、カスタム ビューの drawRect メソッドの外側に描画する必要がある場合があります。
ビューで lockFocus/lockFocusIfCanDraw を呼び出し、現在のコンテキストを要求し、関数の CGContext ファミリ (CoreGrapchis) を使用して実際の描画を行い、最後に CGContextFlush を実行する必要があります (ウィンドウをフラッシュしたり、NSGraphicsContext クラス メソッドを使用して行うこともできます)。フラッシュ)。
この手順は、実際には NSView の -display メソッドを呼び出している場合と同じです。
問題は...「自然な」方法よりも3〜4倍遅いことです(setNeedsDisplayを呼び出すか、Cocoaがこれを行うように要求したときにdrawRectから描画します)。たとえば、ビューの setNeedsDisplay を単純に呼び出すことはできません。この「-display のような」機能が必要です。
テストの例 (タイマーを使用) では、簡単にするために、-display を呼び出しています (一般に、アプリが行うのと同じ作業を行うため) 対 -setNeedsDisplay で、「-display」のタイミングが 3- であることがわかります。 「-setNeedsDisplay」の 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 メソッドには 2 つのセクションがあります。pp ディレクティブで「1」を「0」に変更すると、-display/-setNeedsDisplay の両方を試すことができます。したがって、たとえば、次の出力があります。
-表示: 3.32 秒。(?)
-setNeedsDisplay: 1.2 秒。
「Instruments」アプリによって作成されたコール ツリー/所要時間を見てみましたが、あまり役に立ちませんでした。
編集: うーん、私は今見ることができます:実際には、 setNeedsDisplay ビューはすべてのタイマーイベントで再描画されません!