Macos 如何优化Cocoa绘图以确保平滑滚动

Macos 如何优化Cocoa绘图以确保平滑滚动,macos,cocoa,draw,nsview,Macos,Cocoa,Draw,Nsview,我使用标准的Cocoa绘图API在NSView上绘制图形。见下图。在滚动视图中的NSView上有多个图形。每个图形都有大约1440个数据点,由于正在进行重绘,所以滚动性能有点困难 有没有办法确保图形只绘制一次,以便图像可以平滑地上下滚动 该视图用于生成PDF输出文件 如果图形实际上不需要更改,除非调整视图的大小,而且这种情况不会发生,那么是否有任何方法可以防止视图在滚动期间重新绘制自身。希望有一个简单的开关,以确保视图绘制自己一次,并保持在内存中 基本代码在NSView子类draw()函数中 o

我使用标准的Cocoa绘图API在NSView上绘制图形。见下图。在滚动视图中的NSView上有多个图形。每个图形都有大约1440个数据点,由于正在进行重绘,所以滚动性能有点困难

有没有办法确保图形只绘制一次,以便图像可以平滑地上下滚动

该视图用于生成PDF输出文件

如果图形实际上不需要更改,除非调整视图的大小,而且这种情况不会发生,那么是否有任何方法可以防止视图在滚动期间重新绘制自身。希望有一个简单的开关,以确保视图绘制自己一次,并保持在内存中

基本代码在NSView子类draw()函数中

override func draw(_ dirtyRect: NSRect) {

    drawAxis()

    // Only draw the graph axis during live resize
    if self.inLiveResize {
        return
    }

    plot1()
    plot2()
    plot3()
    ...

 }

 func plot1(){

     for value in plot1Data {

        path = NSBezierPath()

        if isFirst {
           path?.move(to: value)
        } else {
           path?.line(to: value)
        }
     }
 }

苹果在他们的文章中提供了相当全面的建议

看起来你甚至没有采取最小的步骤来避免画你不需要的东西。例如,您显示的代码不会检查
dirtyRect
,以查看给定的绘图是否完全超出它的范围,因此不需要绘制

但是,正如那篇文章中所描述的,使用
getrectsbeingdraw(\uquot:)
和/或
needsToDraw(\uquot:)
方法通常可以做得更好

在某些情况下,滚动视图可以保存已经绘制的内容,这样视图就不需要重新绘制。看。不过,其中的一个要求是,您的视图需要不透明。它需要覆盖
isOpaque
以返回true。不过,仅仅声称自己不透明是不够的。您的视图实际上必须是不透明的,每次调用
draw()
时都要绘制整个脏矩形。在进行其他绘图之前,可以使用背景色填充脏矩形以满足此要求

确保剪辑视图的
copiesOnScroll
属性也设置为true。这可以在IB中完成(尽管它是作为滚动视图的属性显示的),也可以在代码中完成。默认情况下,它应该为true


请注意,作为响应滚动的一部分的透支将在空闲时间内增量发生。这将涉及重复调用视图的
draw()
方法。如果您没有优化它,只绘制与脏rect相交的东西,那么这些调用将非常缓慢/昂贵。所以,一定要进行优化。

苹果在他们的文章中提供了非常全面的建议

看起来你甚至没有采取最小的步骤来避免画你不需要的东西。例如,您显示的代码不会检查
dirtyRect
,以查看给定的绘图是否完全超出它的范围,因此不需要绘制

但是,正如那篇文章中所描述的,使用
getrectsbeingdraw(\uquot:)
和/或
needsToDraw(\uquot:)
方法通常可以做得更好

在某些情况下,滚动视图可以保存已经绘制的内容,这样视图就不需要重新绘制。看。不过,其中的一个要求是,您的视图需要不透明。它需要覆盖
isOpaque
以返回true。不过,仅仅声称自己不透明是不够的。您的视图实际上必须是不透明的,每次调用
draw()
时都要绘制整个脏矩形。在进行其他绘图之前,可以使用背景色填充脏矩形以满足此要求

确保剪辑视图的
copiesOnScroll
属性也设置为true。这可以在IB中完成(尽管它是作为滚动视图的属性显示的),也可以在代码中完成。默认情况下,它应该为true


请注意,作为响应滚动的一部分的透支将在空闲时间内增量发生。这将涉及重复调用视图的
draw()
方法。如果您没有优化它,只绘制与脏rect相交的东西,那么这些调用将非常缓慢/昂贵。所以,一定要进行优化。

好的建议。您还可以查看方法
bitmapImageRepForCachingDisplayInRect:
cacheDisplayInRect:toBitmapImageRep:
。对于这种特殊情况,可能没有必要,但谁知道呢。谢谢,只创建一次所有“NSBezierPath”是否有意义,即将它们存储在一个数组中,然后在该数组上迭代以检查每个路径是否与脏矩形相交,如果是,则调用路径“stroke()”方法?好的建议。您还可以查看方法
bitmapImageRepForCachingDisplayInRect:
cacheDisplayInRect:toBitmapImageRep:
。对于这种特殊情况可能没有必要,但谁知道呢。谢谢,只创建一次所有“NSBezierPath”是否有意义,即将它们存储在一个数组中,然后在该数组上迭代以检查每个路径是否与脏rect相交,如果是,则调用路径“stroke()”方法?