Я заметил странную проблему с моим приложением на основе какао в Mac OS X 10.7. По какой-то причине (не важно здесь) иногда мне приходится рисовать вне метода drawRect моего пользовательского представления.display vs. setNeedsDisplay
Мне нужно позвонить lockFocus/lockFocusIfCanDraw на мой взгляд, спросить текущий контекст, сделать фактический чертеж с семейством функций CGContext (CoreGrapchis), а в конце сделать CGContextFlush (я могу также очистить окно или использовать NSGraphicsContext класс для создания флеша).
Эта последовательность на самом деле такая же, как если бы я вызывал метод отображения NSView.
Проблема в том, что она в 3-4 раза медленнее, чем «естественный» способ (вызовите setNeedsDisplay или рисуйте из drawRect, когда Cocoa попросит вас сделать это). Я не могу просто вызвать, например, setNeedsDisplay для представления, мне нужна эта функция '-display-like'.
В примере теста (который использует таймер), для простоты, я вызываю -display (поскольку он вообще работает с тем же моим приложением) vs -setNeedsDisplay, и я могу видеть время '-display 'в 3-4 раза дольше, чем' -setNeedsDisplay '.
Вот пример моего класса 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 имеет два раздела - если вы измените '1' на '0' в pp-директиве, вы можете попробовать оба варианта -display/-setNeedsDisplay. Итак, у меня есть, например, следующий результат:
-display: 3.32 s. (?)
-setNeedsDisplay: 1.2 s.
Я посмотрел на дерево звонков/время, проведенное с помощью приложения «Инструменты», но это не очень помогло мне.
Редактировать: Хмммм, я могу видеть сейчас: на самом деле, с представлением setNeedsDisplay не перерисовывается на каждом событии таймера!
Итак, setNeedsDisplay устанавливает флаг, но позже AppKit (?) Может игнорировать этот флаг, и представление не перерисовывается? (примерно в 2/3 событий таймера) – user1479515
У меня есть вызовы CoreGraphics здесь, поскольку в моем приложении Cocoa недостаточно для меня, и я использую CoreGrapchis.NSTimer здесь не важен, в моем реальном таймере приложения реализовано не мной, а по-другому, я даже не занимаюсь таймерными событиями, NSTimer здесь только для примитивной «анимации» и показывает, что с -display он медленный. – user1479515