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

Posted

技术标签:

【中文标题】Xcode 9.2 和 Swift 4 中的 AppKit 的 IBDesignable 是不是损坏?【英文标题】:Is IBDesignable broken for AppKit in Xcode 9.2 and Swift 4?Xcode 9.2 和 Swift 4 中的 AppKit 的 IBDesignable 是否损坏? 【发布时间】:2017-12-05 20:28:48 【问题描述】:

与此相关的大多数问题和答案都基于旧版本的 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
    

我向应用程序添加了一个自定义视图,并将 Identity Inspector 中的类属性设置为我的自定义类 (ButtonPresetView)。

它应该在画布上显示按钮,但画布是空白的。 不确定有多少人以这种方式使用它,但它在 Xcode 8.3 中与 Swift 3 完美配合。

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

【问题讨论】:

【参考方案1】:

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

wantsLayer = true
canDrawSubviewsIntoLayer = true

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

【讨论】:

分层是默认开启的,所以wantsLayer = true是不必要的。 我不知道 AppKit 在这方面做出了任何改变。您是否有确认默认值已更改的链接?或者你是说仅仅将canDrawSubviewIntoLayer 设置为true 会打开NSView 自己的层? 对不起,我的措辞是错误的。默认情况下,自定义控件中不启用图层支持。我的意思是说,在一个新的 AppKit 项目中,内容视图默认是层支持的,因此它的所有子视图也是如此。 其实我相信你是对的。 canDrawSubviewIntoLayer 似乎是 Apple 的一项举措,以使 AppKit 渲染模型与 UIKit 渲染模型保持一致。我发现,如果您取消选中 layer-backed content view,canDrawSubviewIntoLayer 也是不必要的,它的工作方式与 xCode 8.3 中的一样。谢谢您的帮助。这让我发疯了。【参考方案2】:

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

canDrawSubviewsIntoLayer 设置为true 时,其所有未专门启用wantsLayer 的子视图将使用将canDrawSubviewsIntoLayer 设置为true 的父视图层呈现其内容。

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

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

【讨论】:

以上是关于Xcode 9.2 和 Swift 4 中的 AppKit 的 IBDesignable 是不是损坏?的主要内容,如果未能解决你的问题,请参考以下文章

使用 xcode 9.2 的情节提要中的不一致错误

Xcode 9.2 卡在编译 Swift 3.2 项目中

为啥应用存档在 iOS、swift、xcode 9.2 中使用自定义框架失败

Xcode 9 Swift 4 Playgrounds UIGestureRecognizer 不工作

Xcode 9.2 中缺少标头搜索路径、库路径和链接路径部分

Xcode 8/Swift 3:让 AP​​I 信息离线可用? [复制]