JKaz JKaz - 6 months ago 28
Swift Question

Does Cocoa connection binding to NSToolbarItem prevent deinitializing?

Trying to set the selected segment of an

NSToolbarItem
that's an
NSSegmentedControl
via connection binding to a property (optionSegment). Subclassing the window controller as such

class MyWindow: NSWindowController {
dynamic var optionSegment: Int = 0

override func windowDidLoad() {
super.windowDidLoad()
}
}


Alternately, put the optionSegment property in the
NSDocument
subclass and bind to that. Each work. The problem is that with this binding, or seemingly any binding to
NSToolbarItem
, none of my objects (views, view controllers, document, etc) will deinitialize. With a binding, they don't. Remove the binding and they do.

Any ideas why this might be so? Suggestions? Quite stumped.

Thank you!

Answer

As Willeke suggested, toolbarItem.view was the path to success. Have to say that the hierarchy of objects is not always clear to me, but .view seemed the only possibility as I looked at the toolbarItem hooks overnight, and Willeke's suggestion confirmed it. The Apple documentation on binding does mention it as our responsibility to unbind some objects, while it unbinds others. Here's the code I put in my NSDocument subclass for unbinding everything, and the view controller is now deinitializing.

func windowWillClose(notification: NSNotification) {
    let wcs = self.windowControllers
    let wc = wcs[0]
    let toolbar = wc.window?.toolbar
    if toolbar != nil {
        let items = toolbar!.items
        for item in items {
            let v = item.view
            if v != nil {
                // print(v?.className)
                let objects = v!.exposedBindings
                for object in objects {
                    // print(object + " " + item.label + " " + v!.className)
                    v!.unbind(object)
                }
            }
        }
    }
}

This was one of the most confusing concepts I've run into--so many moving parts--and thanks to Willeke & stevesliva for the dialog that wound its way to a solution.

From NSObject(NSKeyValueBindingCreation):

All standard bindings on AppKit objects (views, cells, table columns, controllers) unbind their bindings automatically when they are deallocated, but if you create key-value bindings for other kind of objects, you need to make sure that you remove those bindings before deallocation (observed objects have weak references to their observers, so controllers/model objects might continue referencing and messaging the objects that were bound to them).

Comments