14 Apr 2006

quitting a core data app when editing


i came across this really weird behavior in a cocoa core data document-based app that i'm writing. basically, i was encountering a problem where if i was editing in a NSTextView and then press Cmd+Q to quit, then the dialog box would appear asking me to save my changes. if i press save, then the application would hang and seemingly stopped at saving the file.

other observations that are important in this scenario:

1. only happened when the focus (firstResponder) is inside an NSTextView. it would work fine in an NSTableView or NSTextField.
2. the hang would happen right after [NSPersistentDocument saveDocumentWithDelegate:didSaveSelector:contextInfo:]
3. the window was still responsive, i could resume the quit by selecting the NSTableView and then press Cmd+Q again.
4. normal Cmd+S save would work when in NSTextView, not inside the quit loop

solution:

the cause of the problem turned out that the NSTextView was marked to have unsaved data, so during the save on quit process. the cocoa bindings and core data interaction somehow needed prodding to tell it to make sure the UI is consistent with the core data model, and if it wasn't, it would fail silently. why it's not fixing the problem itself, and why this only happens on quit, i do not know.

i found this out because i overrode the setter and getter for attributes in my NSManagedObject subclass that represented my data and observed that in a normal save, the NSTextView data was committed before the save occured, but never when the save was initiated by the quit.

in short, the solution is to make sure when in your NSPersistentDocument subclass, you override canCloseDocumentWithDelegate:shouldCloseSelector:contextInfo: to something like this:

- (void)canCloseDocumentWithDelegate:(id)delegate shouldCloseSelector:(SEL)shouldCloseSelector contextInfo:(void *)contextInfo
{
[[self managedObjectContext] commitEditing];
[super canCloseDocumentWithDelegate:delegate shouldCloseSelector:shouldCloseSelector contextInfo:contextInfo];
}


was just so frustrated with tracking down this bug, that i had to tell someone about it -- even if maybe less than 1% of you actually understand what the hell i'm talking about! this isn't the first obscure quirk that i've had to overcome. the other one i had was with makeFirstResponder, but i'll save that for another time.


You can reply to me about this on Twitter: