iphonememory-leaksconstructorcopycopywithzone

IPhone - copyWithZone leak


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;
 }

Solution

  • 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;