A frustrating problem I came across today when I tried binding an NSPopUpButton’s selection key to an NSArrayController’s selection was that the NSPopUpButton would always display a ‘ghost’ object -one of the opaque classes internal to Cocoa/Core-Data Bindings(<_NSControllerObjectProxy… or similar).
It turns out that NSPopUpButton does not record the user’s selection, so even if I had been able to get rid of the ghost object, I wouldn’t have been able to access the selected object.
The solution is to manually maintain a currently selected object in the window controller - File’s Owner in Interface Builder; in this case, selectedPackage:
In writing HostManager 2.0, I’ve come up against a lot of problems caused by the dark magic that is Cocoa bindings and key-value observing. One of the most troublesome of these has been with transient (calculated) properties.
For example, a Client managed object can get a count of owned domains that are expiring soon. This is a transient propety, accessed through a key of expiringDomains. It simply returns an NSSet which is built from a fetchRequest.
Previously, I was running this fetchRequest each time the key was accessed. This was admittedly inefficient, but seemed functional - at least until you saved the document.
Something crazy happens when a Core Data document is saved - all the objects in a context are released (faulted). There is a good reason for this, as it frees up any memory that was being used to temporarily store the managed objects. However, it caused very strange results to appear in my transient properties; namely, they would all vanish.
Even forcing the fetch request to refresh didn’t pick up any objects from the context (I’m not sure why as I would have expected the faulted objects to be ‘refired’). So I took the plunge and refactored the Client object to cache its expiringDomains value. After some extensive testing and finger-crossing, I’m fairly sure this is the correct way to handle transient relationship properties:
Hours of searching for an answer were beginning to lead me to the conclusion that it was impossible to unfault transient properties of an NSManagedObject after loading them from a datafile.
The Problem: A ’smart’ group to show expiring domains based on their (transient, calculated) isExpiring property worked until the document was saved. On saving, the objects in the context became faults and the smart group no longer worked. This was also true of re-loading a saved document - the domain’s isExpiring property would not be unfaulted.
ame
The Solution: It’s a horrible solution, but seemingly the only way to get the faults to fire (calling [domain will/didAccessValueForKey:@"isExpiring"] did nothing). On awakening the smart group from a fetch, a quick NSFetchRequest is created to fetch all the Domain objects and unfault their @”data” propety. This is no doubt a dirty piece of code, but seems to force the calculated properties to be unfaulted.
With this now working, I can finally continue implementing the business logic in HM2.0, and stop worrying about the intricacies of Core Data and the dark art of Bindings.