views:

75

answers:

3

Testing my app on the device it returns a leak whe i call the copy of a custom object ande i can't understand why.

this is the call:

NSMutableArray *arr = [[NSMutableArray alloc] initWithCapacity:5];
for (SinglePart *sp in [copyFrom partList]) {
    [arr addObject:[sp copy]];
}
self.partList = arr;
[arr release];

this is the method:

- (id)copyWithZone:(NSZone *)zone {
    SinglePart *copy = [[[self class] allocWithZone:zone] initWithSinglePart:self];
    [copy loadImage];
    return copy;
}

this is the method that is called by copyWithZone:

- (id)initWithSinglePart:(SinglePart *)copyFrom {
    if (self = [super init]) {
        self.imagePath = [copyFrom.imagePath copy];
        self.color = [UIColor colorWithCGColor:copyFrom.color.CGColor];
        self.hasOwnColor = copyFrom.hasOwnColor;
        self.blendingMode = copyFrom.blendingMode;
    }
    return self;
 }
+2  A: 

copy returns a new object with retain count 1. Meaning you need to release the new object, which you are not doing.

NSMutableArray *arr = [[NSMutableArray alloc] initWithCapacity:5];
for (SinglePart *sp in [copyFrom partList]) {
    SingPart *theCopy = [sp copy];
    [arr addObject:theCopy];
    [theCopy release];
}
self.partList = arr;
[arr release];

Even your custom copyWithZone: method inits an object, but does not autorelease it, which is the expected behavior of a copy method. Copy must be balanced just like a retain or init, meaning you must balance it with release at some point.

Lastly, your initWithSinglePart: method leaks the imagePath as well. In this case if you declare the imagePath property as copy instead of retain then you don't need to do this manually at all. Then you simply assign the value and let the property setter do it for you.

// Header
@property (copy) NSString *imagePath;

// Now this will do the copy for you
self.imagePath = copyFrom.imagePath;
Squeegy
Thanks really much... i really need to read a bit further about memory management. Can you suggest some link? :)
w4nderlust
http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
fluchtpunkt
A: 

You are making a copy of sp and then adding it to the array. The array then retains the object so your retain count is now 2.

In the end you release arr, thus making the retain count of it's items 1.

You should either add another release to the sp objects, or not use copy.

Try this:

self.partList = [NSMutableArray arrayWithCapacity:5];
for (SinglePart *sp in [copyFrom partList]) {
    [arr addObject:sp];
}
Rengers
+1  A: 

Also, is the property imagePath defined with retain or copy semantics?

If so you need to add an autorelease here:

self.imagePath = [[copyFrom.imagePath copy] autorelease];

because the default setter will retain/copy it too.

So, you either need to autorelease, or omit the "self." to bypass the default setter.

David Gelhar