views:

73

answers:

2

I'm fairly new to Objective-C and am not sure how to correctly deal with memory management in the following scenario:

I have a Core Data Entity with a to-many relationship for the key "children". In order to access the children as an array, sorted by the column "position", I wrote the model class this way:

@interface AbstractItem :  NSManagedObject  
{
    NSArray * arrangedChildren;
}

@property (nonatomic, retain) NSSet * children;
@property (nonatomic, retain) NSNumber * position;
@property (nonatomic, retain) NSArray * arrangedChildren;

@end


@implementation AbstractItem

@dynamic children;
@dynamic position;
@synthesize arrangedChildren;

- (NSArray*)arrangedChildren
{
    NSArray* unarrangedChildren = [[self.children allObjects] retain];
    NSSortDescriptor* sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"position" ascending:YES];
    [arrangedChildren release];
    arrangedChildren = [unarrangedChildren sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
    [sortDescriptor release];
    [unarrangedChildren release];
    return [arrangedChildren retain];
}

@end

I'm not sure whether or not to retain unarrangedChildren and the returned arrangedChildren (first and last line of the arrangedChildren getter). Does the NSSet allObjects method already return a retained array? It's probably too late and I have a coffee overdose.

I'd be really thankful if someone could point me in the right direction. I guess I'm missing vital parts of memory management knowledge and I will definitely look into it thoroughly.

A: 

The retain in your @property for arrangedChildren should take care of that. You will need to release it in your dealloc.

Peter Zich
Thanks for the hint, I forgot to copy the dealloc method to the post as I left out the rest of the class.
Marian André
+3  A: 

-allObjects returns an autoreleased instance, there is no need to retain and release it.

As for arrangedChildren, it will be retained only if you use the synthesized setter:

self.arrangedChildren = [unarrangedChildren sortedArrayUsingDescriptors:/*...*/];

Directly assigning to the instance variable as you do does not invoke the synthesized setter.

Finally, you shouldn't retain the return value here - your method isn't named starting with alloc, new or create and callers thus have to take ownership explicitly.

I recommend reading the "Cocoa Memory Management Guide" and the section on "Declared Properties" in the Objective-C language description.

Georg Fritzsche
I just read through your link to the Object Ownership and Disposal chapter of memory management and I think I understand now. I guess I need to read the whole guide again, as I'm sure I missed alot the first time.Very useful answer! Thanks!
Marian André
Given that you never read the ivar, it seems pointless to have it at all. Make the property readonly and the variable `arrangedChildren` local to the method. Then, as Georg says, don't retain/release unarrangedChildren nor retain arrangedChildren. And you can lose the `@synthesize...` too.
JeremyP