How to add an NSHostingView in Interface Builder

Viewed 174

I have a simple NSHostingView like this:

class HostedCircleView: NSHostingView<Circle> {}

I want to include this HostedCircleView inside a storyboard view.

So I add a custom view to my storyboard and position it using some layout constraints. Then I change it's class to HostedCircleView using the identity inspector.

But IB uses the init?(coder aDecoder: NSCoder) initialiser and this is not implemented by default. So I add the following implementation:

required init?(coder aDecoder: NSCoder) {
    super.init(rootView: Circle())
}

The problem with this is that it completely ignores the coder and that it does not add the desired constraints from IB to my view when I run it. Instead it logs the following error:

Failed to set (contentViewController) user defined inspected property on (NSWindow): Unable to install constraint on view.  Does the constraint reference something from outside the subtree of the view?  That's illegal. constraint:<NSLayoutConstraint:0x60000351a5d0 NSView:0x7f8596416530.bottom == sbapp.Special:0x7f8598023000.bottom   (active)> view:<NSView: 0x7f8596416530>

How can this be solved?

1 Answers

We cannot use it that way, but we can use it as content - ie. we can to use aggregation instead of inheritance (actually as usual in case of SwiftUI).

Here is a demo of possible approach

class HostedCircleView: NSView {  // << use this in Storyboard !!

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        let content = NSHostingView(rootView: Circle())
        content.translatesAutoresizingMaskIntoConstraints = false

        self.addSubview(content)
        content.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
        content.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
        content.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
        content.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
    }
}
Related