Cocoa 显示与设置需要显示

Cocoa 显示与设置需要显示,cocoa,osx-lion,quartz-2d,Cocoa,Osx Lion,Quartz 2d,我注意到我在MacOSX10.7上基于Cocoa的应用程序有一个奇怪的问题。 由于某些原因(这里不重要),有时我不得不在自定义视图的drawRect方法之外进行绘制 我必须在视图上调用lockFocus/lockFocusIfCanDraw,请求当前上下文,使用CGContext函数族(CoreGraphChis)进行实际绘图,最后进行CGContextFlush(我也可以刷新窗口,或者使用NSGraphicsContext类方法进行刷新) 这个序列实际上与我调用NSView的-display方

我注意到我在MacOSX10.7上基于Cocoa的应用程序有一个奇怪的问题。 由于某些原因(这里不重要),有时我不得不在自定义视图的drawRect方法之外进行绘制

我必须在视图上调用lockFocus/lockFocusIfCanDraw,请求当前上下文,使用CGContext函数族(CoreGraphChis)进行实际绘图,最后进行CGContextFlush(我也可以刷新窗口,或者使用NSGraphicsContext类方法进行刷新)

这个序列实际上与我调用NSView的-display方法是一样的

问题是。。。它比“自然”方式慢3-4倍(当Cocoa要求您这样做时,请调用setNeedsDisplay或drawRect)。 例如,我不能简单地调用setNeedsDisplay来查看,我需要这个'-display-like'功能

在一个测试示例(使用计时器)中,为了简单起见,我调用-display(因为它通常与我的应用程序的工作相同)vs-setNeedsDisplay,我可以看到“-display”的计时比“-setNeedsDisplay”长3-4倍

下面是我的CustomView类(实现)的一个示例:

#导入
#导入“CustomView.h”
@实现自定义视图
{
时间间隔起始时间;
n定时器*定时器;
无符号步长;
}
-(id)initWithFrame:(NSRect)帧
{
返回[super initWithFrame:frame];
}
-(void)drawRect:(NSRect)dirtyRect
{
CGContextRef ctx=(CGContextRef)[[NSGraphicsContext currentContext]GraphicsSport];
如果(!计时器)
{
CGContextSetRGBFillColor(ctx,1,1,1,1.);
CGContextFillRect(ctx,dirtyRect);
}
其他的
{
CGContextSetRGBFillColor(ctx,0,0,0,1.);
CGContextFillRect(ctx,CGRectMake(步骤*1.5100,2,2.));
}
}
-(无效)鼠标向下移动:(n事件*)事件
{
如果(!计时器)
{
startTime=CACurrentMediaTime();
计时器=[NSTimer scheduledTimerWithTimeInterval:0.006目标:自选择器:@selector(HandleTime:)用户信息:无重复:是];
步长=0;
}
}
-(无效)handleTimer:(NSTimer*)假人
{
如果(步骤<200)
{
++步骤;
#如果1
[自我展示];
#否则
[自我设置需要显示:是];
#恩迪夫
}
其他的
{
[计时器失效];
定时器=零;
NSLog(@“动画时间为:%g”,caccurrentMediaTime()-startTime);
}
}
@结束
我认为,即使CACurrentMediaTime对于我来说不是很好的函数,它仍然可以显示明显的时差(不需要任何测量就很容易注意到——显示速度非常慢)。 handleTimer方法有两个部分-如果在pp指令中将“1”更改为“0”,则可以同时尝试-display/-setNeedsDisplay。例如,我有以下输出:

-显示:3.32秒。(?)

-设置需要显示:1.2秒

我看了一下“Instruments”应用程序生成的呼叫树/花费的时间,但对我帮助不大

编辑:
Hmmmm,我现在可以看到:实际上,使用setNeedsDisplay视图并不是在每个计时器事件上都重新绘制的

在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驱动动画的方法有点过时了。你应该阅读核心动画的文档来学习如何做这类事情。

在你的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驱动动画的方法有点过时了。您应该阅读Core动画上的文档,以了解如何执行此类操作。

好的,因此setNeedsDisplay设置了该标志,但稍后AppKit(?)可以忽略该标志,并且视图不会重新绘制?(大约在2/3的计时器事件中)我在这里有一个CoreGraphics调用,因为在我的应用程序中,Cocoa对我来说是不够的,我正在使用CoreGraphics。NSTimer在这里并不重要,在我真正的应用程序中,计时器不是由我实现的,而且以另一种方式,甚至不是我来处理计时器事件,NSTimer在这里只是做基本的“动画”,并显示-display的速度很慢。好的,所以setNeedsDisplay设置了标志,但稍后AppKit(?)可以忽略此标志,并且视图没有重新绘制?(大约在2/3的计时器事件中)我在这里有一个CoreGraphics调用,因为在我的应用程序中,Cocoa对我来说是不够的,我正在使用CoreGraphics。NSTimer在这里并不重要,在我真正的应用程序中,计时器不是由我实现的,而且以另一种方式,甚至不是我来处理计时器事件,NSTimer在这里只是做基本的“动画”,并显示-display的速度很慢。