NSMutableArray function call leaking ..? - objective-c

maybe someone can help me finding why his code is leaking ..
im calling the getNotes function, wich is returning a autorelease NSMutableArray
notesArray = [[noteManager getNotes:id] retain];
notesArray is a property declared in my header file
#property (nonatomic, retain) NSMutableArray* notesArray;
this is the stripped version of the getNotes function
- (NSMutableArray*) getNotes:(NSString *)id {
NSMutableArray* rArr = [[NSMutableArray alloc] init];
for (NSString* sNote in noteArray) {
myNote* note = (myNote*)[NSKeyedUnarchiver unarchiveObjectWithFile:sFile];
[rArr addObject:note];
}
return [rArr autorelease];
}
the [rArr addObject:note]; is 100% leaking ..
why? they are all autoreleased?
the myNote class just a class with some properties, nothing special ...

It may be that you already have notes stored in notesArray and they are not getting released before setting it again.
Try changing this
notesArray = [[noteManager getNotes:id] retain];
//to
self.notesArray = [noteManager getNotes:id];

Does notesArray get released at some point? Instead of manually retaining you can use the dot syntax:
self.notesArray = [noteManager getNotes:id];
instead of:
notesArray = [[noteManager getNotes:id] retain];

for (NSString* sNote in noteArray) {
myNote* note = (myNote*)[NSKeyedUnarchiver unarchiveObjectWithFile:sFile];
[rArr addObject:note];
}
Here your notes are autoreleased and shoud not produce memory leak, but autorelease does not happen immediately. This can become a problem in a long loops. You should use your own autorelease pool to avoid such situations. Like this
for (NSString* sNote in noteArray) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
myNote* note = (myNote*)[NSKeyedUnarchiver unarchiveObjectWithFile:sFile];
[rArr addObject:note];
[pool drain];
}

Related

Releasing synthesized property after alloc init

i have a property
//.h
#property (nonatomic, retain) SomeCLass * someSynthInstance;
//.m
#synthesize someSynthInstance = _someSynthInstance;
- (void) foo
{
self.someSynthInstance = [[SomeCLass alloc] init];
//[self.someSynthInstance release]; <- SHOULD I RELEASE HERE???
}
- (void) dealloc
{
self.someSynthInstance = nil;
}
my theory goes, that [alloc, init] creates a count of 1, and the setter, inc that count, so it becomes 2, therefore i should release it, right after
but aim getting exc_bad_access in the application after i changed everything like this, so aim not sure if its ok
you want to be releasing the instance variable rather than the property. so you can do either:
self.someSynthInstance = [[[SomeCLass alloc] init] autorelease]; // puts it in the autoreleasepool so it'll get released automatically at some point in the near future
or
_someSynthInstance = [[SomeCLass alloc] init]; // skip the property
or
self.someSynthInstance = [[SomeCLass alloc] init];
[_someSynthInstance release]; // call release on the instance variable
The standard practice is:
SomeClass *tmpObj = [[SomeClass alloc] init];
self.someSynthInstance = tmpObj;
[tmpObj release];
you should release the class variable instead.. like [_someSynthInstance release]; that should do the trick.
yes you should release after init
SomeCLass *temp = [[SomeCLass alloc] init];
self.someSynthInstance = temp;
[temp release]

Where is the leak here?

I don't understand where is the leak here.
I am querying for a field in the database. After this, I am inserting in a NSMutableArray list.
#property (nonatomic, retain) NSMutableArray *bList;
#property (nonatomic, retain) NSString *icon;//Model
Model *newModel = [[Model alloc] init];
newModel.icon = [NSString stringWithUTF8String:(char *) sqlite3_column_text(compiledStatement, 2)];
[self.bList addObject:newModel];
[newModel release];
And in the end:
- (void)dealloc {
[self.bList release];
[super dealloc];
}
[self.bList release];
Don't do that; either use self.bList = nil; or [bList release], bList = nil;
There doesn't appear to be a leak in that code, unless I'm missing something obvious.
Remember that leaks identifies where the leak was allocated, not where it was leaked. The leak is likely caused by an over-retain elsewhere.
Based on your comment on #murat's answer, If you are doing,
self.blist = [[NSMutableArray alloc] init];
then you are leaking memory as you are taking ownership twice in that line. One by alloc-init and one based on the property (assuming it is retained, mostly should be). In such case releasing it once in dealloc won't balance the retain-release calls. You will have to rather do,
self.blist = [NSMutableArray array];
or
self.blist = [NSMutableArray arrayWithCapacity:100];
You create an instance of array but did not take a memory space for it. For your blist array, allocate a memory space.
self.blist= [[NSMutableArray alloc]init]; // or you can create like
self.blist= [[NSMutableArray alloc]initWithCapacity:100];

Does this code leak?

I just ran my app through the Leaks in Instruments and I am being told that the following code causes leaks, but I don't see how.
I allocate some NSMutableArrays in my viewDidLoad with this code:
- (void)viewDidLoad {
[super viewDidLoad];
self.currentCars = [[NSMutableArray alloc] init];
self.expiredCars = [[NSMutableArray alloc] init];
}
Then I populate these arrays inside of my viewWillAppear method with the following:
[self.currentCars removeAllObjects];
[self.expiredCars removeAllObjects];
for (Car *car in [self.dealership cars]) {
if ([car isCurrent])
[self.currentCars addObject:car];
if ([car isExpired])
[self.expiredCars addObject:car];
}
And later in the code I release these arrays here:
- (void) viewWillDisappear:(BOOL)animated {
if (currentCars != nil) {
[currentCars release], currentCars = nil;
}
if (expiredCars != nil) {
[expiredCars release], expiredCars = nil;
}
[super viewWillDisappear:animated];
}
Any ideas? Thanks!
Your leak is here:
self.currentCars = [[NSMutableArray alloc] init];
self.expiredCars = [[NSMutableArray alloc] init];
Assuming that you declared property accessores like this:
#property(nonatomic, retain) NSMutableArray *currentCars;
#property(nonatomic, retain) NSMutableArray *expiredCars;
In my opinion, the best way to find leaks (other than using Instruments) is to keep track of the retain count manually.
If you were to do that with for example currentCars, you would find your leak easily. Here is what happens:
self.currentCars = [[NSMutableArray alloc] init];
// The 'init' makes the retain count 1.
// 'self.currentCars = ..' translates to the setCurrentCars: method.
// You probably did not implement that method yourself,
// but by synthesizing your property it is automatically implemented like this:
- (void)setCurrentCars:(NSMutableArray *)array {
[array retain]; // Makes the retain count 2
[currentCars release];
currentCars = array;
}
// In your viewWillDisappear: method
[currentCars release], currentCars = nil; // Makes the retain count 1 so the object is leaked.
The solution is simple. Use this:
NSMutableArray *tempMutableArray = [[NSMutableArray alloc] init];
self.currentCars = tempMutableArray;
[tempMutableArray release];
A little sidenote. You shouldn't release your objects in viewWillDisappear:. The recommended place to do that is dealloc. So your code would be:
- (void)dealloc {
[currentCars release], currentCars = nil;
[expiredCars release], expiredCars = nil;
[super dealloc];
}
The problem is (probably) that you are using the property accessors for the initial setting of the arrays in -viewDidLoad. Since well-implemented property accessors will retain the object, you are getting 1 retain from the +alloc and another retain from assigning it. To fix this, you should release your arrays after assigning them or use [NSMutableArray array] to get an autoreleased one to use for your initial assignments.
Unless you're doing something very odd in currentCars, expiredCars, dealership or cars, no, there's no leak there.
Instruments' pointer to the location of a leak isn't necessarily where the object is actually leaked, per se. If I were to guess, I'd say you're probably neglecting to release either currentCars or expiredCars in your dealloc method.

Initializing an instance variable

With an instance variable myArray:
#interface AppController : NSObject
{
NSArray *myArray;
}
Sometimes I see myArray initialized like this:
- (void)init
{
[super init];
self.myArray = [[NSArray alloc] init];
return self;
}
and sometimes I see it with a more complicated method:
- (void)init
{
[super init];
NSArray *myTempArray = [[NSArray alloc] init];
self.myArray = myTempArray
[myTempArray release];
return self;
}
I know that there's no difference in the end result, but why do people bother to do the longer version?
My feeling is that the longer version is better if the instance variable is set up with a #property and #synthesize (possibly because the variable has already been alloced). Is this part of the reason?
Thanks.
If myArray is a property and it's set to retain or copy (as it should be for a property like this), then you'll end up double-retaining the variable when you do this:
self.myArray = [[NSArray alloc] init];
The alloc call sets the reference count to 1, and the property assignment will retain or copy it. (For an immutable object, a copy is most often just a call to retain; there's no need to copy an object that can't change its value) So after the assignment, the object has retain count 2, even though you're only holding one reference to it. This will leak memory.
I would expect to see either a direct assignment to the instance variable
myArray = [[NSArray alloc] init];
Or proper handling of the retain count:
NSArray *newArray = [[NSArray alloc] init];
self.myArray = newArray;
[newArray release];
Or the use of autoreleased objects:
self.myArray = [[[NSArray alloc] init] autorelease]; // Will be released once later
self.myArray = [NSArray array]; // Convenience constructors return autoreleased objects
This is an idiom used in mutators (sometimes called "setters"), but I think you typed it slightly wrong. Usually it looks like this:
-(void)setMyName:(NSString *)newName
{
[newName retain];
[myName release];
myName = newName;
}
The new name is retained, since this instance will need to keep it around; the old name is released; and finally the instance variable is assigned to point to the new name.
I have a feeling you mean this:
NSArray* a = [NSArray arrayWithObjects:#"foo", #"bar", nil];
and this
NSArray* a = [[NSArray alloc] initWithObjects:#"foo", #"bar", nil];
//...
[a release];
With the first style, the static method performs an alloc/init/autorelease on it for you so you don't have to. With the second style, you have more control over when the memory is released instead of automatically releasing when you exit the current block.
That code will crash your application. The second version only copies the pointer then releases the instance. You need to call [object retain] before releasing the reference.

Retaining an object created in an NSThread

I have the following method which is spawned by a call for a new thread (using NSThread):
- (void) updateFMLs {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *temp = [[NSArray alloc] initWithArray:someArrayFromAnotherProcess];
[self performSelectorOnMainThread:#selector(doneLoading:) withObject:temp waitUntilDone:NO];
[pool release];
}
My doneLoading: method looks like this:
- (void) doneLoading:(NSArray *)obj {
myArray = [[NSArray alloc] initWithArray:obj copyItems:NO];
}
The contents of myArray become invalid. How can I preserve the contents of myArray so I can use them later in my app?
P.S. myArray is defined in the class header file.
If your background thread does some work and needs to 'pass' an NSArray to your main thread, then all doneLoading needs to do is:
-(void)doneLoading:(NSArray *)obj
{
[myArray release]; // release the previous array and its objects
myArray = [obj retain];
// now use myArray, refresh tables, etc.
}
There's (likely) no need to make another copy of the array, and that might be the underlying issue. You should also call [temp release] after your performSelector call, since arguments to that are retained already.
If the contents of myArray are becoming valid somehow, then they are being doubly released somewhere. myArray will retain any objects that are added to it. You mentioned that myArray itself is becoming invalid, so try rewriting your background thread and your doneLoading method with this pattern.
Finally you should use [pool drain] in place of [pool release].
The code you posted looks fine, apart from the memory leak in updateFMLs. You're probably over-releasing the objects somewhere else. I'm guessing it would be wherever someArrayFromAnotherProcess is made.
An alternative to the options above would be to declare myArray as an atomic property in the header
#property (atomic,retain) NSArray *myArray;
Then in updateFMLs you should be able to simply call the setter from the secondary thread. Obviously this only works if you are willing to pay the performance penalty for an atomic property.
- (void) updateFMLs {
NSAutoreleasePool *pool - [[NSAutoreleasePool alloc] init];
NSArray *temp = [[NSArray alloc] initWithArray:someArrayFromAnotherProcess];
[self setMyArray:temp];
[temp release];
[pool drain];
}