drawRect: 不为带有 CAMetalLayer 的 NSView 调用

drawRect: Not called for an NSView with a CAMetalLayer

我有一个 layer-backednot layer-hosted)子类 NSView 调用了 MetalView:

import Cocoa
import Metal

class MetalView: NSView {

    // MARK: Properties

    var metalLayer: CAMetalLayer {
        return layer as! CAMetalLayer
    }

    // MARK: - Overrides

    override func awakeFromNib() {
        super.awakeFromNib()
        initialize()
    }

    override func drawRect(dirtyRect: NSRect) {
        super.drawRect(dirtyRect)
        render()
    }

    override func drawLayer(layer: CALayer, inContext ctx: CGContext) {
        super.drawLayer(layer, inContext: ctx)
        render()
    }

    override func displayLayer(layer: CALayer) {
        super.displayLayer(layer)
        render()
    }

    override func makeBackingLayer() -> CALayer {
        return CAMetalLayer()
    }

    override var wantsUpdateLayer: Bool {
        return false
    }

    // MARK: - Initialization

    func initialize() {
        // Layer
        wantsLayer = true
        metalLayer.delegate = self
        metalLayer.device = MTLCreateSystemDefaultDevice()
        metalLayer.pixelFormat = .BGRA8Unorm
        metalLayer.framebufferOnly = true
    }

    // MARK: - Rendering

    func render() {
        // Rendering
        metalLayer.frame = frame
        NSLog("rendering")
    }

}

render 方法未被调用。我尝试将 wantsUpdateLayer 设置为 truerender 方法被调用,我删除了这部分:

wantsLayer = true
metalLayer.delegate = self
metalLayer.device = MTLCreateSystemDefaultDevice()
metalLayer.pixelFormat = .BGRA8Unorm
metalLayer.framebufferOnly = true

来自 wantsLayer 文档:

If the wantsUpdateLayer method returns NO, you should not interact with the underlying layer object directly.

metalLayer 上设置值并将其帧数修改为 "interact[ing] with the underlying layer object directly." 您不能在此配置中执行此操作。该图层不属于您。它属于系统。系统可以随时自由创建这些缓存层。它不必使用它,也不必只有一个。 (Core Animation 通常会创建额外的图层;这是完全正常的。)

如果您想直接与图层交互,您应该将 wantsUpdateLayer 设置为 true,然后在 updateLayer 中实现您的绘图代码。您不应该尝试将 drawRect: 与您直接弄乱的层混合。

有关此问题的另一个版本,请参阅