Problems initializing my subclassed NSManagedObject

Discussion in 'Mac Programming' started by GorillaPaws, May 28, 2010.

  1. GorillaPaws macrumors 6502a

    GorillaPaws

    Joined:
    Oct 26, 2003
    Location:
    Richmond, VA
    #1
    I have controller object that's trying to initialize 2 NSManagedObjects using a custom initialization method and then stick them in an array. When I debug the code, I'm actually getting 2 pointers to the same object so it seems my NSManagedObject subclass is behaving unintentionally like a singleton.

    In my custom initialization method, I'm calling the designated initializer (which I haven't overridden) for the NSManagedObject, as the documentation instructs, so I'm not sure why I'm getting 2 references to the same object.

    Both tClosetRootNode and tPersonRootNode are pointing to the same memory.
    Here is the code that calls the custom Init method:
    Code:
    //	from DISourceListController.m
    -(void) awakeFromNib
    {
    	//appDelegate is an iVar linked as an IBOutlet in IB.  My core data stack is currently living in the appDelegate
    	NSManagedObjectContext *tManagedObjectContext = [appDelegate managedObjectContext];  //  tManagedObjectContext appears valid when debugged
    	
    	DISourceListNode *tClosetRootNode = [[DISourceListNode alloc] initWithName: @"WARDROBE" 
    							      managedObjectContext: tManagedObjectContext
    							      childArrayController: closetArrayController];
    	DISourceListNode *tPersonRootNode = [[DISourceListNode alloc] initWithName: @"PEOPLE" 
    							      managedObjectContext: tManagedObjectContext
    							      childArrayController: personArrayController];
    	
    	rootNodeArray = [[NSArray alloc] initWithObjects: tClosetRootNode,
    							  tPersonRootNode, nil];
    	[tClosetRootNode release];
    	[tPersonRootNode release];	
    	
    	for( DISourceListNode* tArrayItem in rootNodeArray )
    	{
    		NSLog( @"rootNodeArray item is: %s", [tArrayItem valueForKey: @"name"] );
    	}
    	
    	[sourceList reloadData];
    }
    
    
    and here is the init method's code:
    Code:
    //	from DISourceListNode.m
    -(id) initWithName: (NSString *)theName managedObjectContext: theMOC childArrayController: (NSArrayController *)theArrayController
    {
    	NSEntityDescription* tEntityDescription = [NSEntityDescription entityForName: @"DISourceListNode"
    							      inManagedObjectContext: theMOC];
    	//	Call the Designated initializer with the appropriate Parameters
    	[self initWithEntity: tEntityDescription insertIntoManagedObjectContext: theMOC];
    	
    	//	prep the ivars
    	[self setValue: YES forKey: @"isRoot"];
    	[self setValue: theName forKey: @"name"];
    	[self setChildArrayController: theArrayController];
    	[self createChildMArrayWithChildArrayController: theArrayController];
    	
    	NSLog( @"creating DISourceListNode with name: %@", [self valueForKey: @"name"] );
        return self;
    }
    
    Eventually I intend to have more than just these two objects (but I'm trying to get it working first with just these).

    I appreciate any help you can send my way, and I'd be happy to post the full project if you think it would help, although it's still pretty rough.
     
  2. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #2
    Just a wild guess since I haven't done Core Data in about 3 years, but when you call initWithEntity:insertIntoManagedObjectContext: you should assign the return value to self since it's possible for initializers to return a different object:

    Code:
    if (self = [self initWithEntity: tEntityDescription insertIntoManagedObjectContext: theMOC]) {
        [self setValue....
    }
    return self;
     
  3. GorillaPaws thread starter macrumors 6502a

    GorillaPaws

    Joined:
    Oct 26, 2003
    Location:
    Richmond, VA
    #3
    Kainjow, you're the man. I'm getting two objects now--although I've now discovered a bunch of other problems now that my objects are finally initialized properly. Thanks so much for your help!
     
  4. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #4
    I made a test project to figure out what was going on. Basically, alloc returns the same placeholder object for many built-in classes, and init is what returns the actual new object. So if you don't reassign self to the initialized object, you're still pointing to the alloc'd value which explains why both objects were the same. This basically reconfirms the point that you should always assign self to the initialized value and always use init immediately after alloc.

    So the docs are wrong when they say alloc returns "a new instance of the receiver." :)
     
  5. BadWolf13 macrumors 6502

    Joined:
    Dec 17, 2009
    #5
    Hey guys, I know I'm sort of bringing up and old argument, but my question is somewhat related. I'm going to write a program with core-data, as you guys suggested, and as I see it, it's going to require(or at least should have) a subclass of init. Should I take it from your example, that while the init method for a subclass of NSObject always starts with

    Code:
    [super init]
    an NSManagedObject subclass should always call

    Code:
    [self initWithEntity:  insertIntoManagedObjectContext: ];
    within it's init method?
     

Share This Page