Objective C - Memory Management Help

Discussion in 'Mac Programming' started by nashyo, Dec 16, 2011.

  1. macrumors 6502

    nashyo

    Joined:
    Oct 1, 2010
    Location:
    Bristol
    #1
    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
     
  2. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #2
    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).
     
  3. thread starter macrumors 6502

    nashyo

    Joined:
    Oct 1, 2010
    Location:
    Bristol
    #3
    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?
     
  4. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #4
    You release them when you no-longer want them. You should never send another message to an instance after you release it.
     

Share This Page