NSDocument, NSManagedObjectContext do Stuff in -dealloc, Cause Crash
NSDocument, NSManagedObjectContext do Stuff in -dealloc, Cause Crash
- Subject: NSDocument, NSManagedObjectContext do Stuff in -dealloc, Cause Crash
- From: Jerry Krinock <email@hidden>
- Date: Thu, 31 Dec 2009 09:36:47 -0800
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 (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