Xcode 9.2 和 Swift 4 中的 AppKit 是否损坏了 IBDesignable?

Is IBDesignable broken for AppKit in Xcode 9.2 and Swift 4?

与此相关的大多数问题和答案都基于 Xcode 和 Swift 的旧版本。此外,90% 的问题与 UIKit 和绘制自定义控件有关。

我正在添加一个标准按钮,它位于自定义控件的中心,装饰有 IBDesignable

import Cocoa

@IBDesignable public class ButtonPresetView: NSView {
    public override init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
        initialControlSetup()
    }

    public required init?(coder decoder: NSCoder) {
        super.init(coder: decoder)
        initialControlSetup()
    }

    private func initialControlSetup() {
        let button = NSButton(title: "Hello", target: nil, action: nil)
        button.translatesAutoresizingMaskIntoConstraints = false
        addSubview(button)

        // Configure button
        centerXAnchor.constraint(equalTo: button.centerXAnchor).isActive = true
        centerYAnchor.constraint(equalTo: button.centerYAnchor).isActive = true
    }
}

我向应用程序添加了一个自定义视图,并将身份检查器中的 class 属性 设置为我的自定义 class (ButtonPresetView).

它应该显示位于 canvas 中心的按钮,但 canvas 是空白的。 不确定有多少人以这种方式使用它,但它在 Xcode 8.3.

中与 Swift 3 一起工作得很好

还有其他人遇到这个问题吗?

通过将以下两行添加到 initialControlSetup 函数的顶部,我能够在最新的 Xcode 中使用它:

wantsLayer = true
canDrawSubviewsIntoLayer = true

我认为这基本上告诉 NSView 以更类似于 iOS 的工作方式的方式呈现。如果如您所说这在 Xcode 8.3 中有效,则 Apple 可能在 Xcode 9 中引入了此回归而没有意识到。

Dave 的回答是正确的,我只是想记下这个解决方案的后果。

canDrawSubviewsIntoLayer 设置为 true 时,其所有未具体启用 wantsLayer 的子视图将使用带有 canDrawSubviewsIntoLayer 设置为 true.

这意味着子视图动画被禁用,因为它们缺少自己的支持层。为了防止在运行时发生这种情况,您可以将 canDrawSubviewsIntoLayer = true 放入 prepareForInterfaceBuilder() 函数中。

奇怪的是,Interface Builder 不会渲染控件,如果您明确设置 button.wantsLayer = true,根据 "canDrawSubviewsIntoLayer" 文档,它应该为控件提供自己的支持层而不是渲染本身进入父层。 这纯粹是猜测,但我猜测是一种优化,Interface Builder 仅呈现内容视图的顶部 layers/controls。