PDA

View Full Version : Memory leaking worse than a turned on faucet




slooksterPSV
Aug 1, 2006, 10:33 AM
Ok I'm having big issues with memory leakages in my app, I figured out how to change between different accounts on the left side, I uploaded my app in another thread, but here's the updated code that I have for on section.

- (void)showTransactionsForAccount:(id)sender
{
NSLog(@"You chose %d", [accountView selectedRow]);
if([accountView selectedRow] >= 0)
{
NSMutableArray *transAcct = [[NSMutableArray alloc] initWithArray:[[accounts objectAtIndex:
[accountView selectedRow]]transactions]];
NSLog(@"%@", transAcct);
if(transAcct != nil) {
//[transactions release];
transactions = transAcct;
[self setTransactions:transactions];
[tableView setNeedsDisplay:YES];
}
}
}


I'm thinking my leak is with the mutable array being allocated with an array, but never being released. Is there a function where I can put an array in the array without allocating it again?



caveman_uk
Aug 1, 2006, 10:48 AM
NSMutableArray* newArray=[NSMutableArray arrayWithArray: otherArray];

I think that should work. Failing that use [[array mutableCopy] autorelease]

both give should give mutable autoreleased arrays

slooksterPSV
Aug 1, 2006, 10:51 AM
NSMutableArray* newArray=[NSMutableArray arrayWithArray: otherArray];

I think that should work. Failing that use [[array mutableCopy] autorelease]

both give should give mutable autoreleased arrays
I'm grabbing an array from an array, is that bad? So I have an array called Accounts which holds arrays of transactions which hold data.
Accounts->Transactions->name, date, current balance, avail balance, total

EDIT: and the array is being created constantly, like whenever you click on an area, it creates one, click to another it creates another, etc. etc. etc.

EDIT 2: transAcct = [NSMutableArray arrayWithArray:[[accounts objectAtIndex:
[accountView selectedRow]]transactions]];
the program crashes there when you switch back and forth between data cells.

whooleytoo
Aug 1, 2006, 11:35 AM
- (void)showTransactionsForAccount:(id)sender
{
NSLog(@"You chose %d", [accountView selectedRow]);
if([accountView selectedRow] >= 0)
{
NSMutableArray *transAcct = [[NSMutableArray alloc] initWithArray:[[accounts objectAtIndex:
[accountView selectedRow]]transactions]];
NSLog(@"%@", transAcct);
if(transAcct != nil) {
//[transactions release];
transactions = transAcct;
[self setTransactions:transactions];
[tableView setNeedsDisplay:YES];
}
}
}


Ok, there are a few problems here.

- As caveman_uk pointed out, you're creating transAcct each time, and not releasing it.

- You can use arrayWithArray instead, but since that returns an autoreleased array, you may need to retain it (either here, or in setTransactions: ), and release it again later.

- Assuming transactions is an instance variable, do you even need to create another array pointer, "transAcct"? (Not a bug, just a suggestion). You "should" also use an accessor method rather than setting its value directly (it's not compulsory, but it avoids release/retain confusion later).

slooksterPSV
Aug 1, 2006, 12:01 PM
Ok, there are a few problems here.

- As caveman_uk pointed out, you're creating transAcct each time, and not releasing it.

- You can use arrayWithArray instead, but since that returns an autoreleased array, you may need to retain it (either here, or in setTransactions: ), and release it again later.

- Assuming transactions is an instance variable, do you even need to create another array pointer, "transAcct"? (Not a bug, just a suggestion). You "should" also use an accessor method rather than setting its value directly (it's not compulsory, but it avoids release/retain confusion later).

transactions is what holds the transactions when the user creates one, then I want to store that into a variable (which is a NSMutableArray) in my account which holds an array of the transactions.

Account->Transactions->Transaction data
Transactions->Transaction data

I'll try #2 since I have a pretty good idea of what you're saying, but #3, what kind of accessor would I create? one that calls what the long line I have?

EDIT: Errors again now

2006-08-01 11:05:16.868 MDM[2649] You chose 0
2006-08-01 11:05:16.868 MDM[2649] ()
MDM(2649,0xa000ed98) malloc: *** error for object 0x39e1d0: double free
MDM(2649,0xa000ed98) malloc: *** set a breakpoint in szone_error to debug
2006-08-01 11:05:21.739 MDM[2649] You chose 0
2006-08-01 11:05:21.739 MDM[2649] ()
MDM(2649,0xa000ed98) malloc: *** error for object 0x3ac540: double free
MDM(2649,0xa000ed98) malloc: *** set a breakpoint in szone_error to debug


EDIT 2:

transAcct = [NSMutableArray arrayWithArray:[[accounts objectAtIndex:
[accountView selectedRow]]transactions]];

is the line it crashes on when I retain it, store items in it, and then at the end, release it.

EDIT 3:
and it only crashes when there are transactions in each account.

whooleytoo
Aug 1, 2006, 12:07 PM
I'll try #2 since I have a pretty good idea of what you're saying, but #3, what kind of accessor would I create? one that calls what the long line I have?

I'd write it something like this (apologies if I misunderstand what you're trying to do!)


- (void) setTransactionsForAccount: (id) sender
{
if ([accountView selectedRow] >= 0)
{
NSMutableArray* selectedTrans = [NSMutableArray arrayWithArray: [[accountView selectedRow] transactions] ;
if (selectedTrans)
[self setTransactions: selectedTrans] ;
[tableView setNeedsDisplay:YES] ;
}
}

- (void) setTransactions: (NSMutableArray*) transactions
{
if (transactions != _transactions)
{
[_transactions release] ;
_transactions = [transactions retain] ;
}
}

// And, in your dealloc..

- (void) dealloc
{
...
[_transactions release] ;
...
}

slooksterPSV
Aug 1, 2006, 12:10 PM
If you didn't catch Edit 2 and 3, see above or below (whichever you have your threads set on to show)

EDIT:

NSMutableArray* selectedTrans = [NSMutableArray arrayWithArray: [[accounts objectAtIndex:[accountView selectedRow]] transactions]] ;

I had to change it to that, cause accounts is an array, and its taking the object with the location of the selected row which is an array, so it copies that array into the array. So it gets the array in an array. Is that ok?

whooleytoo
Aug 1, 2006, 12:18 PM
If you didn't catch Edit 2 and 3, see above or below (whichever you have your threads set on to show)

If you're having trouble with that line, I'd break it down into its constituents and step through it, and see exactly where the problem is, i.e.


NSMutableArray *transAcct = [[NSMutableArray alloc] initWithArray:[[accounts objectAtIndex:
[accountView selectedRow]]transactions]];


becomes..


int selectedRow = [accountView selectedRow] ;
id account = [accounts objectAtIndex: selectedRow] ;
id array = [account transactions] ;
NSMutableArray* transAcct = [[NSMutableArray alloc] initWithArray: array] ;


It should be pretty obvious at that point where the problem lies.

slooksterPSV
Aug 1, 2006, 12:23 PM
EDIT: Does this mean anything to ya?
If I have 3 accounts, and 2 of them are empty, and I click on one that has data in it, then switch back and forth between the 2 empty ones, nothing happens, but once I click on that one that has data, BAM crashes.

EDIT2: now I just got

2006-08-01 11:33:14.815 MDM[2892] [<Account 0x3a5b00> valueForUndefinedKey:]: this class is not key value coding-compliant for the key date.




NSMutableArray* selectedTrans = [[NSMutableArray alloc] initWithArray: array];

is the problem if I release the object after its done its function. e.g.

NSMutableArray* selectedTrans = [[NSMutableArray alloc] initWithArray: array];
if (selectedTrans)
{
[self setTransactions: selectedTrans];

}
[selectedTrans release];

otherwise it works if I don't release it, but that uses gobs of memory.

whooleytoo
Aug 1, 2006, 12:31 PM
NSMutableArray* selectedTrans = [[NSMutableArray alloc] initWithArray: array];

is the problem if I release the object after its done its function. e.g.

NSMutableArray* selectedTrans = [[NSMutableArray alloc] initWithArray: array];
if (selectedTrans)
{
[self setTransactions: selectedTrans];

}
[selectedTrans release];

otherwise it works if I don't release it, but that uses gobs of memory.


Assuming you need to "hang on to" the selectedTrans array (perhaps to draw another table view?), you can't release it as above; your program would likely crash later on when trying to draw the table view.

Of course, if you don't release it, it just leaks.

I'd recommend using the setTransactions: method I posted above. (You may have other code in your setTransactions: method already, which you could add to mine above). This would ensure that every time you change selection, the old transaction array is released, and the new one retained.

slooksterPSV
Aug 1, 2006, 12:51 PM
I'm uploading the zip file for all of it, maybe you can see what I did wrong.

http://rapidshare.de/files/27817544/MDM_2.zip.html

slooksterPSV
Aug 2, 2006, 12:28 PM
I GOT IT, I GOT IT, IT WORKS YAY!!!
Only one problem left thought :(

Whenever I quit the program it crashes, and it crashes when I try to set the transaction to nil. Not sure if I need to do this, but it does remove observers. Hmm.. I'm going to try remove setTransactions:nil and just release transactions, there are 0 objects in it at the end so yeah.

slooksterPSV
Aug 2, 2006, 01:03 PM
Screenshot!