PDA

View Full Version : Objective C - Memory Management Help




nashyo
Dec 16, 2011, 07:22 AM
I'm having trouble determining why the following code builds, but receives EXC_BAD_ACCESS at the europe object release method call, in the for loop.

I assume it might be because the release is being called multiple times in the while loop? If so, how do I release the europe and england objects?

#import <Foundation/Foundation.h>
#import "Destination.h"

int main (int argc, const char * argv[]) {

NSString* europeText = [[NSString alloc] initWithFormat: @"%@", @"Europe"];
Destination *europe = [[Destination alloc] initWithCountry:europeText andBudget:1000.00 withExchangeRate:1.25];
[europeText release];
NSString* englandText = [[NSString alloc] initWithFormat: @"%@", @"England"];
Destination *england = [[Destination alloc] initWithCountry:englandText andBudget:2000.00 withExchangeRate:1.50];
[englandText release];


for (int n = 1; n < 2; n++) {
double transaction = n*100.00;
NSLog(@"Sending a %.2f cash transaction", transaction);
[europe spendCash:transaction];
NSLog(@"Remaining budget %.2f", [europe leftToSpend]);
NSLog(@"Sending a %.2f cash transaction", transaction);
[england spendCash:transaction];
NSLog(@"Remaining budget %.2f", [england leftToSpend]);
[europe release];
[england release];
}

int n = 1;
while (n < 4) {
double transaction = n*100.00;
NSLog(@"Sending a %.2f credit card transaction", transaction);
[europe chargeCreditCard:transaction];
NSLog(@"Remaining budget %.2f", [europe leftToSpend]);
NSLog(@"Sending a %.2f credit card transaction", transaction);
[england chargeCreditCard:transaction];
NSLog(@"Remaining budget %.2f", [england leftToSpend]);
n++;
[europe release];
[england release];
}

return 0;
}

#import <Cocoa/Cocoa.h>
@class Budget;

@interface Destination : NSObject {

NSString *country;
NSMutableArray *transactions;
Budget *theBudget;
double exchangeRate;
}

- (id) initWithCountry: (NSString*) theCountry andBudget: (double) budgetAmount withExchangeRate: (double) theExchangeRate;
- (void) spendCash: (double) aTransaction;
- (void) chargeCreditCard: (double) aTransaction;
- (double) leftToSpend;

@end

@implementation Destination

- (id) initWithCountry:(NSString *)theCountry andBudget:(double)budgetAmount withExchangeRate:(double)theExchangeRate {

if (self = [super init]) {
transactions = [[NSMutableArray alloc] initWithCapacity:10];
theBudget = [[Budget alloc] initWithAmount:budgetAmount withExchangeRate:theExchangeRate];
country = theCountry;
NSLog(@"I'm off to %@", theCountry);
}
return self;
}

-(void) spendCash: (double)amount {

Transaction *aTransaction = [[CashTransaction alloc] initWithAmount:amount forBudget:theBudget];
[transactions addObject:aTransaction];
[aTransaction spend];
[aTransaction release];
}

-(void) chargeCreditCard: (double) amount {

Transaction *aTransaction = [[CreditCardTransaction alloc] initWithAmount:amount forBudget:theBudget];
[transactions addObject:aTransaction];
[aTransaction spend];
[aTransaction release];
}

- (double ) leftToSpend {

return [theBudget returnBalance];
}

- (void) dealloc {

[transactions release];
[theBudget release];
[country release];
[super dealloc];
}

@end



robbieduncan
Dec 16, 2011, 07:26 AM
In initWithCountry:andBudget:withExchangeRate: you do not retain the country. This is very bad: the Destination instance expects this NSString instance to stay around (it is taking ownership of the instance) but it is not retaining it. You then release this instance you have not retained in the Destination dealloc method: this is another mistake: an object should not release something it has not retained (or created with alloc/init or copy).

nashyo
Dec 16, 2011, 07:55 AM
In initWithCountry:andBudget:withExchangeRate: you do not retain the country. This is very bad: the Destination instance expects this NSString instance to stay around (it is taking ownership of the instance) but it is not retaining it. You then release this instance you have not retained in the Destination dealloc method: this is another mistake: an object should not release something it has not retained (or created with alloc/init or copy).

Thanks. I've added the retain message. It was not a problem without this retain message. Of course, it's good practice to add it anyway.

My problem with europe and england objects, still remains. I have called alloc/init on them, so surely I must release them. But where is the correct place to write that release message?

robbieduncan
Dec 16, 2011, 07:59 AM
My problem with europe and england objects, still remains. I have called alloc/init on them, so surely I must release them. But where is the correct place to write that release message?

You release them when you no-longer want them. You should never send another message to an instance after you release it.