Search code examples
objective-cmemory-leakscopydeep-copy

Objective-c.How to properly handle copy of object so it doesn't creates memory leaks?


I have some memory leaks and I not quite sure what is causing it, but after some testing, it seems like i screw up at copying my object and it's not released properly. Let me tell you first that I'm using ARC and not so long ago i didn't know much about copies or advance memory management so there still is a lot to learn for me. Ok let's throw in some details, I have 2 classes Tree and TreeCell.

Tree:

@interface Tree : NSObject<NSCopying>

//Here we have 2D array that stores pointers to TreeCell objects
@property (retain,nonatomic)NSMutableArray *tree;

//pointersToTree stores copied pointers from tree, 
//it's the same in terms of content but it have different order of rows and columns
@property (retain,nonatomic)NSMutableArray *pointersToTree;

//i don't believe delegate is relevant to my problems (since it's not copied)
@property (weak,nonatomic) id<treeDelagate>delagate;
…

So in short Tree stores 2 the same pointers to each create TreeCell, one of those in each array.

TreeCell:

@interface TreeCell : NSObject<NSCopying>

//ancestors and children stores arrays made of 2 NSNubers 
@property (retain,nonatomic)NSMutableArray * ancestors;
@property (retain,nonatomic)NSMutableArray * children;

@property (retain,nonatomic)NSNumber* boardY;
@property (retain,nonatomic)NSNumber* boardX;
...// there are some more Integers and Booleans

And here is how copy functions looks like, they are both working but im not sure if they are implemented correctly, so starting with Tree:

-(id) copyWithZone: (NSZone *) zone{
    Tree *copy = [[Tree allocWithZone: zone] init];

    //this array will become copy of self.tree
    NSMutableArray* copyOfTree=[[NSMutableArray alloc]init];

    //loop to go thru all stored TreeCell pointers in self.tree
    for (NSInteger a=0; a<self.tree.count; a++) {
     //adding row   
     [copyOfTree addObject:[[NSMutableArray alloc]init]];

        for (NSInteger b=0; b<[self.tree[a] count]; b++) {
            //creating copy of TreeCell and storing pointer to it
            [copyOfTree[a] addObject:[((TreeCell*)self.tree[a][b]) copy]];
        }
    }
    copy.tree=copyOfTree;
    //by now we copied whole self.tree and since i have function to create pointersToTree out of it I call it below
    [copy creatArryOfPointer_Rows:self.pointersToTree.count columns:[self.pointersToTree[0]count]];

    return copy;

}

So what I'm trying to get here is deep copy of Tree. Ok here is TreeCell copy function:

-(id) copyWithZone: (NSZone *) zone{

    //we start here by allocating and setting NSNubers boardY and boardX
    TreeCell* copy = [[TreeCell allocWithZone: zone] initWithLayer:self.layer boardX:self.boardX andBoardY:self.boardY];

    //after that some integers and booleans are set
    copy.helper=self.helper;
    copy.inTree=self.inTree;
    copy.stableConnected=self.stableConnected;
    copy.positon=self.positon;
    copy.freeStoreg=self.freeStoreg;

   // here we are adding arrays containg 2 NSNumbers
    for (int a=0; a<self.ancestors.count; a++) {
        [copy addAncestorWithX:self.ancestors[a][0] andY:self.ancestors[a][1]];
    }
    for (int a=0; a<self.children.count; a++) {
        [copy addChildWithX:self.children[a][0] andY:self.children[a][1]];

    }

    return copy;

}

To make things clear here is addAncestor function addChildren looks the same:

-(void) addAncestorWithX:(NSNumber*)ancestorX andY:(NSNumber*)ancestorY{
    if ([self.ancestors indexOfObject:[NSArray arrayWithObjects:ancestorX,ancestorY, nil]]==NSIntegerMax) {
    [self.ancestors addObject:[NSMutableArray arrayWithObjects:ancestorX,ancestorY, nil]];
    }

Finally this piece of code that creates memory leak:

for (NSInteger a=0; a<8000; a++) {
         Tree* testTree =[self.startingTree copy];
}

At the end of each cycle of this loop testTree should be released, after testing I'm 100% sure that dealloc for it is called and it's also called for each TreeCell that was stored in tree. But memory usage is constantly increasing. Please tell me where did i go wrong. Some paraboly go and say try serializing it but it doesn't cut it for my.


Solution

  • And there i have it! The problem was inside my function for adding children and ancestors.

    [self.ancestors addObject:[NSMutableArray arrayWithObjects:ancestorX,ancestorY, nil]];
    

    This surely added array that i wanted, but it didn't allocate space for it!
    So i changed this code:

    for (int a=0; a<self.ancestors.count; a++) {
            [copy addAncestorWithX:self.ancestors[a][0] andY:self.ancestors[a][1]];
        }
        for (int a=0; a<self.children.count; a++) {
            [copy addChildWithX:self.children[a][0] andY:self.children[a][1]];
    
        }
    

    Into this:

    for (int a=0; a<self.ancestors.count; a++) {
    
            [copy.ancestors addObject:[[NSMutableArray alloc]init]];
            [copy.ancestors[a] addObject:self.ancestors[a][0]];
            [copy.ancestors[a] addObject:self.ancestors[a][1]];
    
        }
        for (int a=0; a<self.children.count; a++) {
    
            [copy.children addObject:[[NSMutableArray alloc]init]];
            [copy.children[a] addObject:self.children[a][0]];
            [copy.children[a] addObject:self.children[a][1]];
    
    
    
        }
    

    So ye folks my tip is when you need deep copy make sure you allocate new space for all of your arrays , and make sure objects don't point outside when they shouldn't.