Managed Object won't dealloc even after Hit with Kitchen Sink
Managed Object won't dealloc even after Hit with Kitchen Sink
- Subject: Managed Object won't dealloc even after Hit with Kitchen Sink
- From: Jerry Krinock <email@hidden>
- Date: Sun, 21 Dec 2008 21:17:44 -0800
REAL-LIFE PROBLEM
In a managed memory application, I have a managed object which,
besides its Core Data managed properties, has a single instance
variable, a worker-kind of object which does some heavy lifting for
it. So that this retained worker, etc., will be deallocced, I need
this managed object to get deallocced when no longer needed.
The documentation [1] seems very clear that, although the 'insert...'
methods return an autoreleased NSManagedObject, a managed object may
be retained by:
(a) the managed object context, until changes are saved
or rolled back, or,
(b) the managed object context's undo manager, as long as
an action involving the managed object remains on
the undo stack.
I conclude that if I save or roll back the moc, and reset the undo
stack, my managed object should be deallocced with the next
autorelease. But despite my repeatedly doing so, these managed
objects never dealloc.
STUDY - DEMO APP
To investigate, I modified Apple's Low-Level Core Data Tutorial into
The World's Simplest Core Data Tool [3] which simply does this:
1. Create a Core Data in-memory stack
2. Disable undo registration
3. Insert a managed object Foo
4. Roll back the moc
5. Save the moc
6. Remove all actions from undo manager
7. Reset the moc
Redundant, I know, but despite my so throwing the kitchen sink at it,
when I then
8. Release the autorelease pool
and expect that my Foo should log a dealloc message, it doesn't happen.
Removing some of the redundant steps does not help. It does dealloc
(with no crash) if I send it TWO release messages.
?????
What am I not understanding? Eric Wing was wondering the same thing,
never got a reply [2].
Thanks,
Jerry Krinock
[1] http://developer.apple.com/DOCUMENTATION/Cocoa/Conceptual/CoreData/Articles/cdMemory.html#/
/apple_ref/doc/uid/TP40001860
[2] http://www.cocoabuilder.com/archive/message/cocoa/2005/9/27/147040
[3] The World's Simplest Core Data Tool
// To see the action, scroll down to main(),
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@interface Foo : NSManagedObject {
}
@end
@implementation Foo
// This is just to log init and dealloc.
- (id)initWithEntity:(NSEntityDescription*)entity
insertIntoManagedObjectContext:(NSManagedObjectContext*)moc {
self = [super initWithEntity:entity
insertIntoManagedObjectContext:moc] ;
NSLog(@"Initted %@", self) ;
return self ;
}
- (void)dealloc {
NSLog(@"Dealloccing %@", self) ;
[super dealloc] ;
}
@end
// Functions to create Core Data Stack
NSManagedObjectModel *managedObjectModel() {
static NSManagedObjectModel *mom = nil;
if (mom != nil) {
return mom;
}
mom = [[NSManagedObjectModel alloc] init];
NSEntityDescription *runEntity = [[NSEntityDescription alloc]
init];
[runEntity setName:@"Foo"];
[runEntity setManagedObjectClassName:@"Foo"];
[mom setEntities:[NSArray arrayWithObject:runEntity]];
return mom;
}
NSManagedObjectContext *managedObjectContext() {
static NSManagedObjectContext *moc = nil;
if (moc != nil) {
return moc;
}
moc = [[NSManagedObjectContext alloc] init];
NSPersistentStoreCoordinator *coordinator =
[[NSPersistentStoreCoordinator alloc]
initWithManagedObjectModel: managedObjectModel()];
[moc setPersistentStoreCoordinator: coordinator];
NSError *error;
NSPersistentStore *newStore ;
newStore = [coordinator
addPersistentStoreWithType:NSInMemoryStoreType
configuration:nil
URL:nil
options:nil
error:&error];
if (newStore == nil) {
NSLog(@"Store Configuration Failure\n%@",
([error localizedDescription] != nil) ?
[error localizedDescription] : @"Unknown Error");
}
return moc;
}
// The action...
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// Get Core Data stack and stuff
NSManagedObjectModel *mom = managedObjectModel();
NSManagedObjectContext *moc = managedObjectContext();
NSUndoManager* undoManager = [moc undoManager] ;
NSEntityDescription *runEntity = [[mom entitiesByName]
objectForKey:@"Foo"];
// Insert a Foo without telling the undo manager
[undoManager disableUndoRegistration] ;
Foo *foo = [[Foo alloc] initWithEntity:runEntity
insertIntoManagedObjectContext:moc];
[moc rollback] ;
// In case rollback was not enough to make that moc give up
// my foo, save the moc
NSError *error = nil;
if (![managedObjectContext() save: &error]) {
NSLog(@"Error while saving\n%@",
([error localizedDescription] != nil)
? [error localizedDescription] : @"Unknown Error");
exit(1);
}
// As a further attempt to make sure that the undo manager
// is not holding a reference to our Foo,
[undoManager removeAllActions] ;
// Now, for a final nail in foo's coffin...
[moc reset] ;
// Now, NOBODY has any reason to hold on to foo, so
// when we release the pool, we expect that Foo should
// log a dealloc message:
[pool release];
// Actual result: no dealloc
// Experiment: If I send foo ^two^ release messages:
// [foo release] ;
// [foo release] ;
// Then it will dealloc, with no crash.
// A third release message,
// [foo release] ;
// will cause a crash.
NSLog(@"Terminating") ;
return 0;
}
_______________________________________________
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