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 (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