I can't comment on the specifics of this because I am not 
knowledgable in that area, but the fact the undo manager is 
getting it's knickers in a twist is surely unrelated to the fact 
_releaseUndoManager was called from [NSDocument dealloc].  I do 
all sorts of things in dealloc methods.  I just try not to write 
buggy code!

I have found that there is a more subtle problem that can arise 
though.  You're never quite sure when a dealloc method might be 
called, especially with the way autorelease pools work, and that 
occasionally means that resources you would like to release 
*right now* hang around longer than you would like them to.  I 
therefore sometimes have a destroy method that I can call any 
time I like.  This releases (in the most general sense) anything 
the object owns that are regarded as critical and leaves the 
object in, effectively, a dormant state.  Then, when dealloc is 
finally called, the object quietly goes away.  I don't have to 
do this very often.  Just for the occasional special case.

Of course, there's nothing to stop you temporarily retaining an 
object in a dealloc method if you need it to stay around while 
you do whatever cleanup you need to do.  Just releae it at the 
end of the method.

Paul Sanders.

----- Original Message ----- 
From: "Jerry Krinock" <je...@ieee.org>
To: "Cocoa Developers" <cocoa-dev@lists.apple.com>
Sent: Thursday, December 31, 2009 5:36 PM
Subject: NSDocument, NSManagedObjectContext do Stuff 
in -dealloc, Cause Crash


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