KVO and XIB file madness

I have been wracking my brain trying to figure out how to handle this exception in my code:


)
2016-07-14 07:17:52.055 WeatherSnoop 4[8336:1392803] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'An instance 0x102461060 of class WSSiteWindowController was deallocated while key value observers were still registered with it. Current observation info: <NSKeyValueObservationInfo 0x10c073250> (
<NSKeyValueObservance 0x10c0733e0: Observer: 0x10c073000, Key path: agent.weatherProperties, Options: <New: NO, Old: NO, Prior: NO> Context: 0x0, Property: 0x10c0731a0>
)'


It's the classic "hey, you're trying to dealloc an object that has an observer" exception. I know why this is happening, but I'm unable to get around it.


Here's what I have:


The class 'WSSiteWindowController' has a property called agent, who in turn has a property called weatherProperties.


After the WSSiteWindowController object is created, it loads a plug-in called PropertiesPlugIn and passes itself as a pointer to that new plug-in. The PropertiesPlugIn itself is subclassed from NSViewController, and has a XIB file which is loaded at the time the view controller's view property is accessed.


Here's the important part: in the PropertiesPlugIn XIB file there is an NSArrayController object whose content property binds to the agent.weatherProperties key of the WSSiteWindowController object.


This works great for feeding data into the NSTabieView that is part of the PropertiesPlugIn. But things get hairy when the WSSiteWindowController window closes.

When that happens, the WSSiteWindowController's dealloc method gets called BEFORE the dealloc method of the PropertiesPlugIn. As a result, the PropertiesPlugIn XIB file doesn't get unloaded and the agent.weatherProperties observation is still in place, thus the exception.


What I would LIKE to do is somehow disassociate the observation in the PropertiesPlugIn's viewWillDisappear method (which is called prior to the dealloc in WSSiteWindowController) but I don't see how. And without having any way of controlling the order in which the objects are deallocated, I get this exception.


If there were a way to force an 'unload' of the XIB file in the PropertiesPlugIn, then this wouldn't be a problem.


Has anyone encountered this strange dependency before? Any suggestions for how to solve this?

Answered by QuinceyMorris in 157022022

Case 1: Pass the agent to the plugin as a separate parameter. The fact that the window controller is the ultimate source seems irrelevant.


Case 2: Pass the plugin manager to the plugin as a separate parameter. There's still a slight code smell here, because it relies on the plugin to pass the plugin manager up to its superclass init, and not store it separately (because of the danger of a retain cycle in code you don't control). One alternative is to pass an opaque "context" parameter instead, which as a matter of private implementation is (or is an object containing a reference to) the plugin manager, which is then exposed as a superclass property after the superclass init.


Case 3: The plugin can find its window via pluginViewController.view.window. Alternatively, provide a "windowForSheet" method in the plugin manager, which may safely have a private, weak reference to the window controller, if you want to arrange things that way.

Thanks Quncey. This is exactly the right advice. I've redesigned the class constructors and properties accordingly so that KVO unregistration is no longer a problem and the exception is eliminated.

KVO and XIB file madness
 
 
Q