我注意到Mac OS X 10.7上基于Cocoa的应用程序存在一个奇怪的问题。 由于某些原因(这里不重要),有时我必须在自定义视图的drawRect方法之外绘制。
我必须在我的视图上调用lockFocus / lockFocusIfCanDraw,询问当前上下文,用CGContext函数系列实现绘图(CoreGrapchis),最后再做CGContextFlush(我也可以刷新窗口,或者使用NSGraphicsContext类做冲洗的方法。)
这个序列实际上和我调用NSView的-display方法一样。
问题是......它比“自然”方式慢3-4倍(当Cocoa要求你这样做时,调用setNeedsDisplay或从drawRect中绘制)。 我不能简单地为一个视图调用setNeedsDisplay,我需要这个'-display - like'功能。
在一个测试示例(使用计时器)中,为了简单起见,我调用-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。
我查看了“乐器”应用程序生成的调用树/花费的时间,但它对我没什么帮助。
编辑: 嗯,我现在可以看到:实际上,在每个计时器事件中都没有重新绘制setNeedsDisplay视图!
答案 0 :(得分: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,前者使绘图立即发生,后者设置一个标志,每次通过事件循环,如果该标志为真,窗口将发送-display到相关视图并清除旗帜。
还有一件事:这种使用NSTimer来驱动动画的方法有点过时了。你应该阅读关于核心动画的文档来学习如何做这种事情。