Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

nashyo

macrumors 6502
Original poster
Oct 1, 2010
299
0
Bristol
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?

Code:
#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;
}

Code:
#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

Code:
@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

Moderator emeritus
Jul 24, 2002
25,611
893
Harrogate
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

macrumors 6502
Original poster
Oct 1, 2010
299
0
Bristol
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

Moderator emeritus
Jul 24, 2002
25,611
893
Harrogate
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.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.