不使用 draw(_ updateRect: NSRect) 函数直接在 NSView 中绘图

Drawing directly in a NSView without using the draw(_ updateRect: NSRect) function

我想将 CGImage 图片直接绘制到 View 中,使用绘图函数的常规方法我在新的 Mac Book Pro 上每秒只能获得 7 张图片。所以我决定改用 updateLayer 函数。我已经定义了 wantsUpdateLayer = true 并且我的新 updateLayer 函数被按预期调用。但随后开始了我的问题。使用 draw func 时,我使用“NSGraphicsContext.current?.cgContext”获取当前 CGContext,但在我的 updateLayer func 中,“NSGraphicsContext.current?.cgContext”为 nil。所以我不知道把我的 CGImage 放在哪里,它会显示在我的屏幕上。此外,“self.view?.window?.graphicsContext?.cgContext”和“self.window?.graphicsContext?.cgContext”也为零。此视图中没有按钮或其他元素,在视图的 window 中,只有一张图片,填满了完整的 window。而这张图,一秒钟要变30次。生成图片由一个单独的线程完成,一张图片大约需要 1 毫秒。我认为从 NSView class 的“外部”无法写出图片,但我的 updateLayer 函数在 class.

内部

下面是 func 的实际样子:

override func updateLayer ()
{
    let updateRect: NSRect = NSRect(x: 0.0, y: 0.0, width: 1120.0, height: 768.0)
    let context1 = self.view?.window?.graphicsContext?.cgContext
    let context2 = self.window?.graphicsContext?.cgContext
    let context3 = NSGraphicsContext.current?.cgContext
}

并且在我设置needsDisplay标志后自动调用该函数时,所有三个上下文都为nil。

知道在哪里绘制我的 CGImages 吗?

updateLayer 函数由用户界面自动调用。我不手动调用它。它由视图调用。我的问题是在这个方法中将我的图片显示在屏幕上的位置。也许我必须添加一个图层或使用视图的默认图层,但我不知道该怎么做。

与此同时,我从一个好朋友那里找到了解决方案:

override var wantsUpdateLayer: Bool
{ 
    return (true)
}

override func updateLayer ()
{
    let cgimage: CGImage? = picture // Here comes the picture
    if cgimage != nil
    {
        let nsimage: NSImage? = NSImage(cgImage: cgimage!, size: NSZeroSize)
        if nsimage != nil
        {
            let desiredScaleFactor: CGFloat? = self.window?.backingScaleFactor
            if desiredScaleFactor != nil
            {
                let actualScaleFactor: CGFloat? = nsimage!.recommendedLayerContentsScale(desiredScaleFactor!)
                if actualScaleFactor != nil
                {
                    self.layer!.contents      = nsimage!.layerContents(forContentsScale: actualScaleFactor!)
                    self.layer!.contentsScale = actualScaleFactor!
                }
            }
            
        }
    }
}

这是直接写入图层的方式。根据格式(CGImage 或 NSImage),您首先必须转换它。一旦 func wantsUpdateLayer returns 为真,就会使用 func updateLayer() 而不是 func draw()。就这些了。

所有想看我的“普通”绘图功能的人:

override func draw (_ updateRect: NSRect)
{
    let cgimage: CGImage? = picture // Here comes the picture
    if cgimage != nil
    {
        if #available(macOS 10.10, *)
        {
            NSGraphicsContext.current?.cgContext.draw(cgimage!, in: updateRect)
        }
    }
    else
    {
        super.draw(updateRect)
    }
}

额外的速度是 2 倍或更多,具体取决于您使用的硬件。在现代的 Mac Pro 上,速度只有一点点,但在现代的 Mac Book Pro 上,您将获得 10 倍或更多的速度。这适用于 Mojave 10.14.6 和 Catalina 10.15.6。我没有用旧的 macOS 版本测试它。 “普通”绘图功能适用于 10.10.6 至 10.15.6。