NSPersistentDocument objects "gutted" after Duplicate, Rename in 10.9
NSPersistentDocument objects "gutted" after Duplicate, Rename in 10.9
- Subject: NSPersistentDocument objects "gutted" after Duplicate, Rename in 10.9
- From: Jerry Krinock <email@hidden>
- Date: Fri, 07 Mar 2014 08:30:23 -0800
This message regards my SQLite NSPersistentDocument-based app, which has adopted Auto Save and Versions but not Asynchronous Saving, legacy delete/rollback SQLite journaling, built with OS X 10.9 SDK, manual memory management. Its document data model has a singular “document options” object, which has a couple dozen attributes including about six date attributes and one relationship.
Steps to reproduce:
• Click in the menu: File > Duplicate. As expected, new document window pops out of the old, and filename in the title bar has keyboard focus.
• Type in a new name.
• End editing.
• Execute code which attempts to get any of those date attributes, or that relationship, or set any attribute.
Result: EXC_BAD_ACCESS. (See CALL STACK below.) Getting a string or number attribute works OK. The singular object is neither faulted nor deleted. Its -retainCount is 14. I’m calling it “gutted”. Poking with the debugger, I saw indications that other objects in the store might be “gutted" too.
Running the same build in OS X 10.8 works fine.
Can anyone explain technically this “gutted” state?
I think this is probably another bug in NSPersistentDocument. It might be another facet of the bugs in which the store options to request legacy delete/rollback journaling are not being passed up the stack in non-lightweight migration (Apple Bug 15854533) or File > Duplicate (Apple Bug 16038419). (We fixed those with a method swizzle in NSPersistentStoreCoordinator.)
I know about the open-source BSManagedDocument as a replacement for NSPersistentDocument. If this app were not so big and old, I would replace NSPersistentDocument with BSManagedDocument. I will certainly start my next app with BSManagedDocument.
A workaround is to immediately close and re-open the document and window after such a duplicate-and-rename. Out of the box, NSPersistentDocument does this during a Revert operation, unlike NSDocument which simply refreshes the existing document and window. So it is not surprising that the same behavior is necessary for reliable operation after a duplicate-and-rename. You can detect the duplicate-and-rename by overriding -[NSDocument saveToURL:ofType:forSaveOperation:completionHandler:] and testing for the existing -fileURL to be nil, prior to invoking super. In all other operations I have tested, it is not nil. I tested the following operations:
File > Open
File > New
File > Save As
File > Move To
File > Rename
File > Revert to > Last Saved
File > Revert to > Browse All Versions, restore old version
File > Revert to > Browse All Versions, just click “Done"
So I’m getting ready to ship an update with this workaround. I hope I didn’t miss any corner cases.
Thanks for reading,
Jerry
CALL STACK (Attempt to set a BOOL attribute of gutted object)
EXC_BAD_ACCESS (code=1, address=0x60)
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 com.apple.CoreData _propertyAtIndexForEntityDescription + 16
1 com.apple.CoreData snapshot_get_value_as_object + 237
2 com.apple.CoreData -[NSManagedObject(_NSInternalMethods) _newPropertiesForRetainedTypes:andCopiedTypes:preserveFaults:] + 312
3 com.apple.CoreData -[NSManagedObject(_NSInternalMethods) _newAllPropertiesWithRelationshipFaultsIntact__] + 90
4 com.apple.CoreData -[NSManagedObjectContext(_NSInternalChangeProcessing) _establishEventSnapshotsForObject:] + 56
5 com.apple.CoreData _PFFastMOCObjectWillChange + 190
6 com.apple.CoreData _PF_ManagedObject_WillChangeValueForKeyIndex + 249
7 com.apple.CoreData -[NSManagedObject willChangeValueForKey:] + 101
8 com.mycompany.myframework 0x000000010002490c -[Bookshig setIgnoreDisparateDupes:] + 64 (DocOptions.m:233)
9 com.apple.CoreData _PF_Handler_Public_SetProperty + 68
10 com.apple.Foundation 0x00007fff863991d4 -[NSObject(NSKeyValueCoding) setValue:forKeyPath:] + 343
11 com.apple.AppKit -[NSObjectController _setSingleValue:forKeyPath:] + 105
12 com.apple.Foundation 0x00007fff8639919a -[NSObject(NSKeyValueCoding) setValue:forKeyPath:] + 285
13 com.apple.AppKit -[NSBinder _setValue:forKeyPath:ofObject:mode:validateImmediately:raisesForNotApplicableKeys:error:] + 364
14 com.apple.AppKit -[NSBinder setValue:forBinding:error:] + 245
15 com.apple.AppKit -[NSValueBinder _applyObjectValue:forBinding:canRecoverFromErrors:handleErrors:typeOfAlert:discardEditingCallback:otherCallback:callbackContextInfo:didRunAlert:] + 194
16 com.apple.AppKit -[NSValueBinder applyDisplayedValueHandleErrors:typeOfAlert:canRecoverFromErrors:discardEditingCallback:otherCallback:callbackContextInfo:didRunAlert:error:] + 621
17 com.apple.AppKit -[NSValueBinder performAction:] + 288
18 com.apple.AppKit -[_NSBindingAdaptor _objectDidTriggerAction:bindingAdaptor:] + 133
19 com.apple.AppKit -[NSControl sendAction:to:] + 56
20 com.apple.AppKit -[NSCell _sendActionFrom:] + 128
21 com.apple.AppKit -[NSCell trackMouse:inRect:ofView:untilMouseUp:] + 2316
22 com.apple.AppKit -[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:] + 487
23 com.apple.AppKit -[NSControl mouseDown:] + 706
24 com.apple.AppKit -[NSWindow sendEvent:] + 11296
25 com.mycompany.myframework 0x00000001000a8e13 -[SSYWindow sendEvent:] + 71 (SSYWindow.m:10)
26 com.apple.AppKit -[NSApplication sendEvent:] + 2021
27 com.apple.AppKit -[NSApplication run] + 646
28 com.apple.AppKit NSApplicationMain + 940
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden