views:

43

answers:

2

I've started cleaning up my app before publication - using "Instruments" Leak analyzer.

I found a leak I can't plug. So I built a simple project to illustrate the problem. Please see code below. I put a button on the view to test fire the procedure "test". It always generates a leak.

First the header and code for an object named "theObj"

#import <Foundation/Foundation.h>


@interface theObj : NSObject {

NSString* theWord; } @property (nonatomic,retain) NSString* theWord;

@end

#import "theObj.h"


@implementation theObj
@synthesize theWord;

-(id) initWithObjects: (NSString *) aWord;
{
 if (self = [super init]){
  self.theWord = aWord;
 }
 return self;
}

-(void) dealloc{
[theWord release];
[super dealloc];
}

@end

Now the view controller

#import <UIKit/UIKit.h>
#import "theObj.h"

@interface LeakAnObjectViewController : UIViewController {
 NSMutableArray* arrObjects;
}
  - (IBAction)test;
@end

#import "LeakAnObjectViewController.h"

@implementation LeakAnObjectViewController

- (IBAction)test {  
 if (arrObjects == nil)
  arrObjects = [[NSMutableArray alloc] init];

 NSString* aStr = @"first";
 [arrObjects addObject:[[theObj alloc] initWithObjects:aStr]];
 [arrObjects removeAllObjects];
}  
A: 

You alloc the object, which means you own it. Then you give it to the array, which means the array owns it as well. Then the array removes it, so you are the only owner. But you don't have a reference to the object anymore, so you can't release it, so it's just leaked.

Chuck
So I changed the code in an attempt to release the offending string - but it still generates a leak. - (IBAction)test { if (arrObjects == nil) arrObjects = [[NSMutableArray alloc] init]; NSString* aStr = @"first"; [arrObjects addObject:[[theObj alloc] initWithObjects:aStr]]; [arrObjects removeAllObjects]; [aStr release];
@manateeman: Um, you just added a release for `aStr`. Your `[theObj alloc]` is still not balanced with a release. You need to do `id temp = [[theObj alloc] initWithObjects:aStr]; [arrObjects addObject:temp]; [temp release];`.
Chuck
OK Chuck - many thanks - that resolved the leak in the test project. I really don't have any excuse for not seeing the tree except that the forest is in the way. Now I'll go back to the real world and see if I can do some good for my app.
A: 

Someone really needs to learn the rules around memory management. Specifically as it pertains to ownership, etc.

jer
Please believe me - I have read it 3 times today alone - not to mention past encounters. What floors me is that if I add the line [aStr release]; it has no effect - still it leaks.
You need to make sure that you use autorelease where appropriate, retain where appropriate, etc. If you just use alloc/init without autoreleasing, then you need to make sure you have a reference around after you are done with it that you can release it yourself. You take complete ownership of that object when you do things this way. If you are putting things in collections, you shouldn't do it this way. This is all covered in the rules I linked to.
jer