Search code examples
swiftcocoacocoa-bindingsnstoolbaritemdeinit

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!


Solution

  • 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
        if wcs.count == 0 { return }
        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).