I remember reading that the only safe thing to do in your dealloc method is to 
release instance variables.  If you look at lines #23 - #25 in the call stack 
below, it appears that NSDocument's -dealloc is doing more, sending 
-removeAllActions to its undo manager.  Similarly, lines #7 and #8 say that 
NSManagedObjectContext's -dealloc is removing tasks which target itself from 
its undo manager.

Now I must admit that I have often found it difficult to find a place other 
than -dealloc to remove observations and dependencies like this, and have 
gotten away with it on occasion.  In this case, however, it seems to result in 
a crash upon closing a Core Data document with unsaved changes (whether saving 
or not), when using a custom undo manager.

Here is how I see the steps in the crash:

*  During its -dealloc, NSDocument sends itself _releaseUndoManager, which 
sends -removeAllActions to the document's undo manager.
*  The undo manager sends -removeAllObjects to its undo stack.
*  The first group in the undo stack is deallocced.
*  The NSInvocation owned by the group is deallocced.
*  Now, here's where things start getting hairy.  The NSInvocation has retained 
the NSManagedObjectContext because it is its target.  And, as things happen, 
this is apparently the last retain on the NSManagedObjectContext, because at 
this point, it deallocs.
*  Within -dealloc, the managed object context sends several messages, finally 
resulting in -removeAllActionsWithTarget: being sent to the undo manager.
*  So that it can iterate through the stacks, the undo manager's 
-removeAllActionsWithTarget: starts out by attempting to make a copy of the 
undoStack, which is still in the process of having all of its objects removed.  
Crash.

So, to solve this problem, I implemented a lockout kludge, an ivar 
mIsCleaningStacks, in the undo manager.  Its -removeAllActions locks it out 
while it is removing objects from its undo and redo stacks, and if 
removeAllActionsWithTarget: sees this it doesn't touch them.  I believe this is 
otherwise harmless, since these stacks are in the process of having all their 
objects removed anyhow.

Is this a good case study in why "the only safe thing to do in your dealloc 
method is to release instance variables", or have I misunderstood the problem?

Does a better workaround pop into anyone's mind?  The crash does not occur when 
using Apple's NSUndoManager, which I presume must also have some workaround 
built into it.

Thanks,

Jerry Krinock

#0      0x015f96ce in __CFTypeCollectionRetain
#1      0x016490b0 in CFArrayCreateCopy
#2      0x0028ee31 in -[NSCFArray copyWithZone:]
#3      0x016587ea in -[NSObject(NSObject) copy]
#4      0x0012f318 in -[GCUndoGroup removeTasksWithTarget:] at 
GCUndoManager.m:1107
#5      0x0012d89d in -[GCUndoManager removeAllActionsWithTarget:] at 
GCUndoManager.m:477
#6      0x01b4b3f1 in -[NSManagedObjectContext(_NSInternalNotificationHandling) 
_stopObservingUndoManagerNotifications]
#7      0x01b7c78e in -[NSManagedObjectContext(_NSInternalNotificationHandling) 
_unregisterForNotifications]
#8      0x01b7c5c1 in -[NSManagedObjectContext dealloc]
#9      0x01b695ca in -[NSManagedObjectContext release]
#10     0x015ff528 in CFRelease
#11     0x016298b2 in __CFArrayReleaseValues
#12     0x015ff6f1 in _CFRelease
#13     0x0166d19a in -[NSInvocation dealloc]
#14     0x0012f9cf in -[GCConcreteUndoTask dealloc] at GCUndoManager.m:1289
#15     0x015ff528 in CFRelease
#16     0x016298b2 in __CFArrayReleaseValues
#17     0x015ff6f1 in _CFRelease
#18     0x0012f614 in -[GCUndoGroup dealloc] at GCUndoManager.m:1183
#19     0x015ff528 in CFRelease
#20     0x016298b2 in __CFArrayReleaseValues
#21     0x0165644e in CFArrayRemoveAllValues
#22     0x0012d7e0 in -[GCUndoManager removeAllActions] at GCUndoManager.m:455
#23     0x00127c52 in -[SSYDooDooUndoManager removeAllActions] at 
SSYDooDooUndoManager.m:101
#24     0x009a63eb in -[NSDocument _releaseUndoManager]
#25     0x009a6898 in -[NSDocument dealloc]
#26     0x00b05b8c in -[NSPersistentDocument dealloc]
#27     0x00115705 in -[Bkmslf dealloc] at Bkmslf.m:2024
#28     0x015ff528 in CFRelease
#29     0x0162c0ed in _CFAutoreleasePoolPop
#30     0x00288dd6 in NSPopAutoreleasePool
#31     0x00288cfe in -[NSAutoreleasePool drain]
#32     0x0060e55f in -[NSApplication run]
#33     0x00606535 in NSApplicationMain
#34     0x00001e67 in main at MainApp-Main.m:19

_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to