Will Richardson
Will Richardson

Reputation: 7960

Add multiple subviews to NSWindow in Swift

I have a window with an outlet and a custom view (in my .xib file) which contains a button and a text field. When a button is pressed in the window I want to add an instance of the custom view into the window.

Currently I have an outlet to the window and the custom view (configWindow and customView) and this action is called when the button is pressed:

@IBAction func addView(sender: NSButton) {
    configWindow.contentView.addSubview(customView)
    // Print the views in the window, see what's been added
    for i in configWindow.contentView.subviews {
        println(i)
    }
}

This will only ever add one view to the window.

Is this the right way to go about it, or should I be using a completely different approach?

Upvotes: 1

Views: 1549

Answers (1)

Abizern
Abizern

Reputation: 150605

You can't add the same view twice. It sounds like you are trying to add the same instance of customView to configWindow multiple times, which you can't do. If you think about it, it's fairly obvious why -- how will the superview manage two subviews which are the same? How will it know the difference between the two of them?

You should be adding different instances of the CustomView class instead:

@IBAction func addView(sender: NSButton) {
    let customView = CustomView(frame: <some frame>)

    configWindow.contentView.addSubview(customView)
    // Print the views in the window, see what's been added
    for i in configWindow.contentView.subviews {
        println(i)
    }
}

Edited to add I've created an example project that you can download at https://bitbucket.org/abizern/so-27874883/get/master.zip

This basically initialises multiple views out of a nib file and adds them randomly to a view.

The Interesting part is:

class CustomView: NSView {

    @IBOutlet weak var label: NSTextField!

    class func newCustomView() -> CustomView {
        let nibName = "CustomView"

        // Instantiate an object of this class from the nib file and return it.
        // Variables are explicitly unwrapped, since a failure here is a compile time error.
        var topLevelObjects: NSArray?
        let nib = NSNib(nibNamed: nibName, bundle: NSBundle.mainBundle())!
        nib.instantiateWithOwner(nil, topLevelObjects: &topLevelObjects)

        var view: CustomView!

        for object: AnyObject in topLevelObjects! {

            if let obj = object as? CustomView {
                view = obj
                break
            }
        }

        return view
    }
}

Where I create a factory method of the custom class that loads itself from the nib, and then returns the first top level object of the correct class.

Upvotes: 2

Related Questions