Challenge - advanced questions


#1

It seemed like a good idea at the time…

I decided to take the challenge and extend it. I set up for loops to create StockHoldings and ForeignStockHoldings and all of their values. I then used a nested for loop to create portfolios and randomly assign StockHolding and ForeignStockHoldings to each Portfolio. Now I can not for the life of me figure out how to get a currentValue of each portfolio. I have tried to write a method in my Portfolio.h file, however when I attempt to access the values I have set for each stock I get a “use of undeclared identifier” error when I set up a fast enumeration in the same way. And I have no idea what to do in the fast enumeration that will work. If I reference any method from my StockHolding and ForeignStockHolding files I get an unknown selector error (even though I have included those files in my Profile files). Can anyone look at this and tell me how I would program to calculate current stock values of my randomized portfolio stocks?

I have included StockHoldings.m and .h and ForeignStockHoldings.m and .h for clarity, but the problem lies in Portfolio.h.

Any and all help appreciated!

Thanks,
Chantel

StockHolding.m and .h

[code]#import <Foundation/Foundation.h>

@interface StockHolding : NSObject

{
float purchaseSharePrice;
float currentSharePrice;
int numberOfShares;
int label;
}

@property float purchaseSharePrice, currentSharePrice;
@property int numberOfShares, label;

  • (float) costInDollars;

  • (float) valueInDollars;

@end

#import “StockHolding.h”

@implementation StockHolding

@synthesize purchaseSharePrice, currentSharePrice, numberOfShares, label;

  • (float) costInDollars
    {
    return purchaseSharePrice * numberOfShares;
    }

  • (float) valueInDollars
    {
    return currentSharePrice * numberOfShares;
    }

@end[/code]

ForeignStockHoldings.m and .h

[code]#import <Foundation/Foundation.h>
#import “StockHolding.h”

@interface ForeignStockHolding : StockHolding

{
float conversionRate;
}

@property float conversionRate;

@end

#import “ForeignStockHolding.h”

@implementation ForeignStockHolding

@synthesize conversionRate;

  • (float) costInDollars
    {
    return purchaseSharePrice * numberOfShares * conversionRate;
    }

  • (float) valueInDollars
    {
    return currentSharePrice * numberOfShares * conversionRate;
    }

@end[/code]

Portfolio.m and .h --> The Problem Child

[code]#import <Foundation/Foundation.h>
#import “StockHolding.h”
#import “ForeignStockHolding.h”

@interface Portfolio : NSObject

{
unsigned int portfolioID;
unsigned int currentValue;
}

@property unsigned int portfolioID, currentValue;

  • (void) addStockObject: (StockHolding *) a;

  • (void) addForeignStockObject: (ForeignStockHolding *) a;

  • (float) portfolioCurrentValue;

@end

#import “Portfolio.h”

@implementation Portfolio

@synthesize portfolioID, currentValue;

/* Method to create array as add stock to each portfolio within the portfolio array */

  • (void) addStockObject:(StockHolding *)a
    {
    NSMutableArray *stockArray = [[NSMutableArray alloc]init];
    [stockArray addObject: a];
    }

/* Method to create an array to add each foreign stock to each portfolio within the portfolio array */

  • (void) addForeignStockObject:(ForeignStockHolding *)a
    {
    NSMutableArray *foreignStockArray = [[NSMutableArray alloc]init];
    [foreignStockArray addObject: a];
    }

/* MY PROBLEM CHILD METHOD /
/
Attempting to do fast enumeration of each stock valueInDollars.
In Chapter 19 programming example we created a method in Employee.m and defined it in Employee.h that used both an array (assets) set up in the same way I have done here and methods we imported from Asset.h as seen below:

  • (unsigned int) valueOfAssets;
    {
    unsigned int sum = 0;
    for (Asset *a in assets)
    {
    sum += [a resaleValue];
    }
    return sum;
    }

    So why doesn’t the same thing work here?? And how do I calculate the currentValue if I can’t access valueInDollars of my stocks??? */

  • (float) portfolioCurrentValue
    {
    float sum = 0;
    for (StockHolding *a in stockArray) // Use of undeclared identifier error
    {
    unsigned int sum = 0;
    sum += [a valueInDollars];

    }
    return sum;

}

  • (NSString *) description
    {
    return [NSString stringWithFormat: @“Portfolio #%i: Current value of all stocks:”, [self portfolioID]];

}

@end[/code]

Main

[code]#import <Foundation/Foundation.h>
#import “StockHolding.h”
#import “ForeignStockHolding.h”
#import “Portfolio.h”

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

@autoreleasepool


{
    
    /* Create a mutable array to hold stock creations. Set label, purchaseSharePrice, CurrentSharePrice, NumberOfShares, and valueInDollars for each. Then add each stock to the array. */ 
    
    NSMutableArray *stocks = [[NSMutableArray alloc]init];
    
    for (int i = 0; i < 20 ; i++)
    {
        StockHolding *b = [[StockHolding alloc]init];
        for (int i = 0; i < 20; i++)
        {
            [b setLabel: i];
            [b setPurchaseSharePrice: 10 + i];
            [b setCurrentSharePrice: (10*i)+i / 2];
            [b setNumberOfShares: 3 + i];
            [b valueInDollars];
           
        }
        [stocks addObject: b];
    }
    
    
    
    
    
    /* Create foreign stock holdings and all values */
    
    NSMutableArray *foreignStocks = [[NSMutableArray alloc]init];
    
    for (int i = 0; i < 5; i++)
    {
        ForeignStockHolding *c = [[ForeignStockHolding alloc]init];
        for (int i = 0; i < 5; i++)
        {
            [c setLabel: i];
            [c setPurchaseSharePrice: 10 + 1];
            [c setCurrentSharePrice:(10*i) + i /2];
            [c setNumberOfShares: 3 + i];
            [c setConversionRate: 0.9];
            [c valueInDollars];
        }
        
        [foreignStocks addObject: c];
    }
    
    
    
    
    /* Create portfolios and put randomized stocks and foreign stocks in each. */
    
    NSMutableArray *portfolio = [[NSMutableArray alloc]init];   // Array for 10 portfolios
    
    for (int i = 0; i < 10; i++)
    {
        Portfolio *p = [[Portfolio alloc]init];     // Create p to hold each as goes through loop
        
        [p setPortfolioID: i];                      // set portfolio ID in integer form
        
        for (int i = 0; i < 10; i++)

        {
            
            NSUInteger randomIndex = random() % [stocks count];             // random stock and add to portfolio
            
            StockHolding *randomStock = [stocks objectAtIndex: randomIndex];
            
            [p addStockObject: randomStock];                
            
            for (int i = 0; i < 5; i++)
            {
                NSUInteger randomIndex = random() % [foreignStocks count];  // random foreign stock and add
                
                ForeignStockHolding *randomForeignStocks = [foreignStocks objectAtIndex: randomIndex];
                
                [p addForeignStockObject: randomForeignStocks];
                
               
            }

        }


        [portfolio addObject: p];       // add each portfolio to array
    }
    
    
    NSLog(@"Portfolios: %@", portfolio);
    
}
return 0;

}[/code]


#2

I don’t quite understand what you are trying to do, but I will point out two programming errors.

Problem 1 - creating arrays in the local scope and adding objects to them:

//  Portfolio.m
...

@implementation Portfolio
...
/*  Method to create array as add stock to each portfolio within the portfolio array */
- (void)addStockObject:(StockHolding *)a
{
    NSMutableArray *stockArray = [[NSMutableArray alloc]init]; 
    [stockArray addObject: a];
}

/* Method to create an array to add each foreign stock to each portfolio within the portfolio array */
- (void)addForeignStockObject:(ForeignStockHolding *)a
{
    NSMutableArray *foreignStockArray = [[NSMutableArray alloc]init];
    [foreignStockArray addObject: a];
}
...

Each time one of the above methods is invoked, an array is created in the local scope and an object is added to it. This array and the object in it are lost for ever because the array is created in the local scope.

To correct the error, create an array object that is an instance variable of a Portfolio object:

//  Portfolio.m

#import "Portfolio.h"

@interface Portfolio ()
{
    NSMutableArray *_stockArray;
    NSMutableArray *_foreignStockArray;
}
@end

@implementation Portfolio

@synthesize portfolioID, currentValue;

/*  Method to create array as add stock to each portfolio within the portfolio array */
- (void)addStockObject:(StockHolding *)a
{
    // If not already created, create the array lazily
    if (!_stockArray)
        _stockArray = [[NSMutableArray alloc]init];
    
    [_stockArray addObject: a];
}

/* Method to create an array to add each foreign stock to each portfolio within the portfolio array */
- (void)addForeignStockObject:(ForeignStockHolding *)a
{
    // If not already created, create the array lazily
    if (!_foreignStockArray)
        _foreignStockArray = [[NSMutableArray alloc]init];
    
    [_foreignStockArray addObject: a];
}

Now, the array objects will last as long as the Portfolio object is alive.

Problem 2 - use of undeclared identifier assets and type Asset:


/* MY PROBLEM CHILD METHOD */
- (unsigned int)valueOfAssets;
{
     unsigned int sum = 0;
     for (Asset *a in assets)
     {
     sum += [a resaleValue];
     }
     return sum;
}

assets, used as a container, is not declared anywhere. It should be declared as an instance variable of the Portfolio:

//  Portfolio.m

#import "Portfolio.h"

@interface Portfolio ()
{
    ...
    NSMutableArray *_assets;
}
@end

@implementation Portfolio
...
- (unsigned int)valueOfAssets;
{
     unsigned int sum = 0;
     for (Asset *a in _assets)
     {
     sum += [a resaleValue];
     }
     return sum;
}
...

Also it needs to be populated with asset objects; furthermore, you need an Asset class in order to create asset objects.

Make sure that you understand the meanings of local variables, global variables, instance variables, and last but not least, class variables.


#3

Thank you once again - I am very happy to finally understand why my NSMutableArrays were disappearing!