Soution for Holding Portfolio Challenge from Ch21 in 2nd Ed


#1

Hi all, first post here.

Been going through the chapters and loving it so far.

Found most of it pretty easy to migrate to, coming from a fair C background.

This chapter (21 in the second edition book) has definitely been the most challenging for me, so I thought I’d post up my solution to see if there are any areas for improvement.

The BNRStockHolding and BNRForeignStockHolding classes remain the same, except for the stock ticker property.

My BNRPortfolio header looks like:

#import <Foundation/Foundation.h>
@class BNRStockHolding;

@interface BNRPortfolio : NSObject

{
    NSMutableArray *_stocks;
}

@property (nonatomic, copy) NSString *owner;
@property (nonatomic, copy) NSArray *stocks;
@property (nonatomic) float totalStockValue;

-(void)addStock:(BNRStockHolding *)s;
-(float)totalStockValue;

@end

And the implementation:

#import "BNRPortfolio.h"
#import "BNRStockHolding.h"

@implementation BNRPortfolio

// Accessors for stocks properties
-(void)setStocks:(NSArray *)s
{
    _stocks = [s mutableCopy];
}

-(NSArray *)stocks
{
    return [_stocks copy];
}

-(void)addStock:(BNRStockHolding *)s
{
    // Check if I have no stocks first
    if (!_stocks) {
        
        // If I don't then create the array
        _stocks = [[NSMutableArray alloc] init];
    }
    [_stocks addObject:s];
}

-(float)totalStockValue
{
    float sum = 0.0;
    for (BNRStockHolding *s in _stocks) {
        sum += [s valueInDollars];
    }
    return sum;
}

-(NSString *)description
{
    return [NSString stringWithFormat:@"<Owner: %@, Value: %.2f>", self.owner, self.totalStockValue];
}

@end

And my main file is as below:

#import <Foundation/Foundation.h>
#import "BNRForeignStockHolding.h"
#import "BNRPortfolio.h"

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

    @autoreleasepool {
        
        BNRPortfolio *portfolioUK = [[BNRPortfolio alloc] init];
        BNRPortfolio *portfolioUS = [[BNRPortfolio alloc] init];

        BNRForeignStockHolding *lloyds = [[BNRForeignStockHolding alloc] init];
        [lloyds setNumberOfShares:40];
        [lloyds setPurchaseSharePrice:2.30];
        [lloyds setCurrentSharePrice:4.5];
        [lloyds setConversionRate:0.65];
        [lloyds setSymbol:@"LLYDS"];
        [portfolioUK addStock:lloyds];
        
        BNRForeignStockHolding *bt = [[BNRForeignStockHolding alloc] init];
        [bt setNumberOfShares:10];
        [bt setPurchaseSharePrice:20];
        [bt setCurrentSharePrice:25];
        [bt setConversionRate:0.65];
        [bt setSymbol:@"BT"];
        [portfolioUK addStock:bt];
        
        BNRStockHolding *google = [[BNRStockHolding alloc] init];
        [google setNumberOfShares:10];
        [google setPurchaseSharePrice:400];
        [google setCurrentSharePrice:412.2];
        [google setSymbol:@"GOOG"];
        [portfolioUS addStock:google];
        
        BNRStockHolding *apple = [[BNRStockHolding alloc] init];
        [apple setNumberOfShares:15];
        [apple setPurchaseSharePrice:70];
        [apple setCurrentSharePrice:450];
        [apple setSymbol:@"AAPL"];
        [portfolioUS addStock:apple];
        
        BNRStockHolding *fbook = [[BNRStockHolding alloc] init];
        [fbook setNumberOfShares:20];
        [fbook setPurchaseSharePrice:35];
        [fbook setCurrentSharePrice:45];
        [fbook setSymbol:@"FBK"];
        [portfolioUS addStock:fbook];
    
        NSLog(@"Portfolio for UK has a value of £%.2f", [portfolioUK totalStockValue]);
        NSLog(@"Portfolio for US has a value of $%.2f", [portfolioUS totalStockValue]);
    }
    return 0;
}

Then to the log I get:

Portfolio for UK has a value of £279.50
Portfolio for US has a value of $11772.00

Have I got it about right?

Thanks, Adam


#2

I’m sure there was a reply from someone on this page last time I checked!

If I remember correctly, there were suggestions for improvement too?>>


#3

Hi, I started the 2nd edition of this book as well and wish there were an updated solutions section. Oh well.

I had a question about your code. Why do you declare both a totalStocksValue float as well as a method? Couldn’t you just do the same logic to assign the instance variable totalStocksValue and use dot notation to access the value from main()?


#4

code was awesome made sense thank you.


#5

A little confused as to where to post solutions, using 2nd ed… but this seems on topic anyway!
My solution to the stocks challenge sticks to the basics, but here it is. I tried to use an NSMutableArray to allow for enhancements like easily adding more stocks etc., but haven’t worked it out just yet…

stockHolding interface:

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

@interface BNRStockHolding : NSObject

@property (nonatomic) float purchaseSharePrice;
@property (nonatomic) float currentSharePrice;
@property (nonatomic) int numberOfShares;
@property (nonatomic) NSString *stockName;

  • (float) costInDollars;
  • (float) valueInDollars;

@end[/code]

and implementation:

#import "BNRStockHolding.h"

@implementation BNRStockHolding

-(float) costInDollars {
    return self.purchaseSharePrice*self.numberOfShares;
}

-(float) valueInDollars{
    return self.currentSharePrice*self.numberOfShares;
}

@end

and main…


#import <Foundation/Foundation.h>
#import "BNRStockHolding.h"
int main(int argc, const char * argv[])
{

    @autoreleasepool {
        
        BNRStockHolding *stockA = [[BNRStockHolding alloc]init];
        stockA.purchaseSharePrice=2.30;
        stockA.currentSharePrice=4.50;
        stockA.numberOfShares=40;
        stockA.stockName = @"IBM";
        
        
        BNRStockHolding *stockB = [[BNRStockHolding alloc]init];
        stockB.purchaseSharePrice=12.19;
        stockB.currentSharePrice=10.56;
        stockB.numberOfShares=90;
        stockB.stockName = @"GlaxoSmithKline";
        
        
        BNRStockHolding *stockC = [[BNRStockHolding alloc]init];
        stockC.purchaseSharePrice=45.10;
        stockC.currentSharePrice=49.51;
        stockC.numberOfShares=210;
        stockC.stockName = @"Qinetik";
        
        
        NSArray *stockList = @[stockA,stockB,stockC];
    
        for (BNRStockHolding *s in stockList) {
        
            NSLog(@"\nThe value of holdings of %@ is $%.2f.\n",s.stockName, s.valueInDollars);
            
        }
    }
    
    return 0;
}

At least it helps me understand properties more!


#6

Ok I now see all the chapter sections in the forum comply with the 2nd ed, back on track!
So here is my solution for the holding portfolio challenge.
Interface for BNRStockHolding,

#import <Foundation/Foundation.h>

@interface BNRStockHolding : NSObject

@property (nonatomic) float purchaseSharePrice;
@property (nonatomic) float currentSharePrice;
@property (nonatomic) int numberOfShares;
@property (nonatomic, copy) NSString *stockName;
@property (nonatomic, copy) NSString *tickerAbbr;

- (float) costInDollars;
- (float) valueInDollars;

@end

and its implementation:


#import "BNRStockHolding.h"

@implementation BNRStockHolding


-(float) costInDollars {
    return self.purchaseSharePrice*self.numberOfShares;
}

-(float) valueInDollars{
    return self.currentSharePrice*self.numberOfShares;
}


@end

interface for BNRPortfolio:

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

@interface BNRPortfolio : NSObject

{
    NSMutableArray *_portfolio;
}

@property (nonatomic, copy) NSArray *portfolio;

-(void) addStockHolding:(BNRStockHolding *)stock;
-(float) valueOfPortfolio;
-(float) costOfPortfolio;
-(void) portfolioInfo;


@end

I used the declaration/implementation of the assets array in the chapter as a model, but don’t really understand the need to declare the property NSArrray *portfolio, or the setPortfolio instance method in the implementation. When I comment them out it seems to make no difference…
Th BNRPortfolio implementation:

#import "BNRPortfolio.h"

@implementation BNRPortfolio

-(void) setPortfolio:(NSArray *)stock
{
    _portfolio = [stock mutableCopy];
}

- (NSArray *)portfolio
{
    return [_portfolio copy];
}

-(void) addStockHolding:(BNRStockHolding *)stock
{
    if (!_portfolio){
        _portfolio = [[NSMutableArray alloc]init];
    }
    [_portfolio addObject:stock];
}

-(float) valueOfPortfolio
{
    float valueNow = 0;
    float purchaseValue = 0;
    for (BNRStockHolding *s in _portfolio) {
        valueNow += s.valueInDollars;
        purchaseValue += s.costInDollars;
    }
    return valueNow;
}

-(float) costOfPortfolio
{
    float purchaseValue = 0;
    for (BNRStockHolding *s in _portfolio) {
        purchaseValue += s.costInDollars;
    }
    return purchaseValue;
}


- (void) portfolioInfo
{
    for (BNRStockHolding *s in _portfolio)
    {
   NSLog(@"%@  %@ Purchase:$%.2f Current:$%.2f Holding:%d shares Value:$%.2f",s.stockName, s.tickerAbbr, s.purchaseSharePrice, s.currentSharePrice, s.numberOfShares, s.valueInDollars);
    }
    NSLog(@"\nCost of portfolio was $%.2f.\nValue of portfolio is $%.2f\n", [self costOfPortfolio],[self valueOfPortfolio]);
    
    if ([self costOfPortfolio]>[self valueOfPortfolio]) {
        NSLog(@"\nBernie why aren't you answering my calls?");
    }else {
        NSLog(@"\nWarren you are awesome!");
    }
    
}
@end

and main.m:

#import <Foundation/Foundation.h>
#import "BNRPortfolio.h"
#import "BNRStockHolding.h"

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

    @autoreleasepool {
        
//Create an instance of BNRPortfolio
            BNRPortfolio *aPortfolio =[[BNRPortfolio alloc]init] ;

  
//Fill the new portfolio with stock holdings
        //Create a pool of stock names
            NSString *wordString = [NSString stringWithContentsOfFile:@"/usr/share/dict/words" encoding:NSUTF8StringEncoding error:NULL];
            NSArray *words = [wordString componentsSeparatedByString:@"\n"];
    
            for (int i=0; i<2000; i++) {
        //Creat instance of single stock holding
            BNRStockHolding *stock = [[BNRStockHolding alloc]init];
                    
        //Generate randomish values for stock holdings
            stock.purchaseSharePrice = (arc4random()%10000)/100;
            stock.currentSharePrice =stock.purchaseSharePrice*(0.5+(arc4random()%100)/100.00);
            stock.numberOfShares = arc4random()%500;
            stock.stockName =[[NSString stringWithFormat:@"%@", words[arc4random()%[words count]]]capitalizedString];
                if ([stock.stockName length]<4) {
                    stock.tickerAbbr = [stock.stockName uppercaseString];
                }else{
            stock.tickerAbbr =[[stock.stockName substringToIndex:3] uppercaseString];
                }
        //add stock holding to the new portfolio
            [aPortfolio addStockHolding:stock];
        }

//Print the contents of the portfolio and its current value
        
        [aPortfolio portfolioInfo];
       
        }
    
    
    return 0;
}

In which I generate some fancy names and values from random words.
The whole thing seems to work (although I took out the foreign listings and forgot to put it back yet!), but I don’t know if there’s superfluous code in there and/or incorrect design re.encapsulation etc. Any comments welcomed.


#7

Here is my solution. I played a little with the description methods of BNRStockHolding , BNRForeignStockHolding, and BNRPortfolio. Hope it helps.

BNRForeignStockHolding.h

[code]#import “BNRStockHolding.h”

@interface BNRForeignStockHolding : BNRStockHolding
@property (nonatomic) float conversionRate;
@end[/code]

BNRForeignStockHolding.m

[code]#import “BNRForeignStockHolding.h”

@implementation BNRForeignStockHolding

  • (float)costInDollars
    {
    return [super costInDollars] * [self conversionRate];
    }

  • (float)valueInDollars
    {
    return [super valueInDollars] * [self conversionRate];
    }

  • (NSString *)description
    {
    return [NSString stringWithFormat:@"%@ ; Conversion rate: %.2f", [super description], self.conversionRate];
    }

@end
[/code]

BNRStockHolding.h

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

@interface BNRStockHolding : NSObject

@property (nonatomic) float purchaseSharePrice;
@property (nonatomic) float currentSharePrice;
@property (nonatomic) int numberOfShares;
@property (nonatomic, copy) NSString *symbol;

  • (float)costInDollars;
  • (float)valueInDollars;
    @end[/code]

BNRStockHolding.m

[code]#import “BNRStockHolding.h”

@implementation BNRStockHolding

  • (void)setNumberOfShares:(int)n
    {
    _numberOfShares = n;
    }

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

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

  • (NSString *)description
    {
    return [NSString stringWithFormat:@“Purchase price: %.2f ; Current price: %.2f ; No. of shares: %d ; Cost in dollars: %.2f ; Value in dollars: %.2f ; Symbol: %@”, self.purchaseSharePrice, self.currentSharePrice, self.numberOfShares, self.costInDollars, self.valueInDollars, self.symbol];
    }

@end[/code]

BNRPortfolio.h

[code]#import <Foundation/Foundation.h>
@class BNRStockHolding;

@interface BNRPortfolio : NSObject
{
NSMutableArray *_holdings;
}
@property (nonatomic, copy) NSArray *holdings;

  • (void)addHolding:(BNRStockHolding *)s;
  • (float)totalValue;

@end[/code]

BNRPortfolio.m

[code]#import “BNRPortfolio.h”
#import “BNRStockHolding.h”

@implementation BNRPortfolio

  • (void)setHoldings:(NSArray *)h
    {
    _holdings = [h mutableCopy];
    }

  • (NSArray *)holdings
    {
    return [_holdings copy];
    }

  • (void)addHolding:(BNRStockHolding *)s
    {
    if (!_holdings)
    {
    _holdings = [[NSMutableArray alloc] init];
    }
    [_holdings addObject:s];
    }

  • (float)totalValue
    {
    float sum = 0;

    for (BNRStockHolding *s in _holdings)
    {
    sum += [s valueInDollars];
    }
    return sum;
    }

  • (NSString *)description
    {
    return [NSString stringWithFormat:@"<Portfolio value: %.02f>", self.totalValue];
    }

@end
[/code]

main.m

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

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

@autoreleasepool {
    BNRPortfolio *myPortfolio = [[BNRPortfolio alloc] init];
    
    for (int i = 0; i < 2; i++) {
        BNRStockHolding *s = [[BNRStockHolding alloc] init];
        
        s.purchaseSharePrice = 10 + 5 * i;
        s.currentSharePrice = 5 + 10 * i;
        s.numberOfShares = 10 + 10 * i;
        NSString *currentSymbol = [NSString stringWithFormat:@"NYSE%d", i];
        s.symbol = currentSymbol;
        [myPortfolio addHolding:s];
    }
    BNRForeignStockHolding *f = [[BNRForeignStockHolding alloc] init];
    
    f.purchaseSharePrice = 12;
    f.currentSharePrice = 13;
    f.numberOfShares = 5;
    f.symbol = @"FWB";
    f.conversionRate = 0.94;
    
    [myPortfolio addHolding:f];
    
    NSLog(@"%@", myPortfolio);
    
    for (int i = 0; i < myPortfolio.holdings.count; i++)
    {
        NSLog(@"%@", myPortfolio.holdings[i]);
        
    }
}
return 0;

}[/code]


#8

From what I can gather Aframes code seems pretty spot on in terms of replicating a similar method to how the book went through the BNREmployee example. Now I am pretty new to objective C and found this chapter the hardest so far.I would be really grateful if some one could explain a couple of things for me please.

1/ What is the point of *owner in the BNRPortfolio header?
2/ I’m struggling to get my head over the whole implementation process in general, I can see similarities emerge when comparing to the BMITime example but I think its fair to say I don’t fully get the execution. If someone could shed a lot of light on this and maybe do a step by step guide to why each step is made then I would be very grateful.

Cheers


#9

Try setting breakpoints in the BMITime program to get a sense of what’s going on. Breakpoints make it a LOT clearer.

[quote=“wfsbrown”]From what I can gather Aframes code seems pretty spot on in terms of replicating a similar method to how the book went through the BNREmployee example. Now I am pretty new to objective C and found this chapter the hardest so far.I would be really grateful if some one could explain a couple of things for me please.

1/ What is the point of *owner in the BNRPortfolio header?
2/ I’m struggling to get my head over the whole implementation process in general, I can see similarities emerge when comparing to the BMITime example but I think its fair to say I don’t fully get the execution. If someone could shed a lot of light on this and maybe do a step by step guide to why each step is made then I would be very grateful.

Cheers[/quote]


#10

Here’s mine. It’s running but I always welcome tips from those that have more experience.
I’m still not completely grasping the use copy and mutableCopy.

BNRStockHolding.h

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

@interface BNRStockHolding : NSObject

@property (nonatomic) float purchaseSharePrice;
@property (nonatomic) float currentSharePrice;
@property (nonatomic) int numberOfShares;
@property (nonatomic) NSString *tickerSymbol;

// Methods

  • (float)costInDollars;
  • (float)valueInDollars;

@end
[/code]

BNRStockHolding.m

[code]#import “BNRStockHolding.h”

@implementation BNRStockHolding

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

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

@end[/code]

BNRForeignStockHolding.h

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

@interface BNRForeignStockHolding : BNRStockHolding

@property (nonatomic) float conversionRate;

@end[/code]

BNRForeignStockHolding.m

[code]#import “BNRForeignStockHolding.h”

@implementation BNRForeignStockHolding

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

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

@end[/code]

BNRPortfolio.h

[code]#import <Foundation/Foundation.h>
@class BNRStockHolding;

@interface BNRPortfolio : NSObject
{
NSMutableArray *_portfolio;
}

@property (nonatomic, copy) NSArray *portfolio;

// Methods

  • (float)currentValue;
  • (void)addStockHolding:(BNRStockHolding *) s;
  • (int)arrayCount;
  • (void)displayPortfolio;

@end[/code]

BNRPortfolio.m

[code]#import “BNRPortfolio.h”
#import “BNRStockHolding.h”

@implementation BNRPortfolio

  • (void)setPortfolio:(NSArray *)portfolio
    {
    _portfolio = [portfolio mutableCopy];
    }

  • (NSArray *)portfolio
    {
    return [_portfolio copy];
    }

  • (float)currentValue
    {
    float totalValue = 0.0;
    for (BNRStockHolding *s in _portfolio) {
    totalValue += [s valueInDollars];
    }

    return totalValue;
    }

  • (void)addStockHolding:(BNRStockHolding *)s
    {
    if (!_portfolio) {
    _portfolio = [[NSMutableArray alloc] init];
    }

    [_portfolio addObject:s];
    }

  • (int)arrayCount {
    return (int)[_portfolio count];
    }

  • (void)displayPortfolio {
    for (BNRStockHolding *s in _portfolio) {
    NSLog(@"\n%@ \nPurchase Share Price: %.2f \nNumber Of Shares: %d \nCurrent Share Price: %.2f \nCurrent Value: $%.2f", [s tickerSymbol], [s purchaseSharePrice], [s numberOfShares], [s currentSharePrice], [s valueInDollars]);
    }
    }

@end[/code]

main.m

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

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

@autoreleasepool {
    
    BNRPortfolio *myStockPortfolio = [[BNRPortfolio alloc] init];
    
    
    BNRStockHolding *riverview = [[BNRStockHolding alloc] init];
    BNRStockHolding *apple = [[BNRStockHolding alloc] init];
    BNRStockHolding *google = [[BNRStockHolding alloc] init];
    BNRForeignStockHolding *euroApple = [[BNRForeignStockHolding alloc] init];
    BNRForeignStockHolding *euroRiverView = [[BNRForeignStockHolding alloc] init];
    BNRForeignStockHolding *euroGoogle = [[BNRForeignStockHolding alloc] init];
    
    
    
    [riverview setPurchaseSharePrice:2.50];
    [riverview setCurrentSharePrice:3.19];
    [riverview setNumberOfShares:1000];
    [riverview setTickerSymbol:@"RVSB"];
    
    [apple setPurchaseSharePrice:311.02];
    [apple setCurrentSharePrice:512.09];
    [apple setNumberOfShares:40];
    [apple setTickerSymbol:@"AAPL"];
    
    
    [google setPurchaseSharePrice:800.22];
    [google setCurrentSharePrice:1118.33];
    [google setNumberOfShares:2];
    [google setTickerSymbol:@"GOOG"];

    
    [euroApple setPurchaseSharePrice:10.10];
    [euroApple setCurrentSharePrice:110.10];
    [euroApple setNumberOfShares:400];
    [euroApple setConversionRate:2.00];
    [euroApple setTickerSymbol:@"EAPL"];
    
    
    [euroRiverView setPurchaseSharePrice:11.11];
    [euroRiverView setCurrentSharePrice:111.11];
    [euroRiverView setNumberOfShares:400];
    [euroRiverView setConversionRate:3.00];
    [euroRiverView setTickerSymbol:@"ERVR"];
    
    
    [euroGoogle setPurchaseSharePrice:12.12];
    [euroGoogle setCurrentSharePrice:112.12];
    [euroGoogle setNumberOfShares:400];
    [euroGoogle setConversionRate:4.00];
    [euroGoogle setTickerSymbol:@"EGOO"];
    
    [myStockPortfolio addStockHolding:riverview];
    [myStockPortfolio addStockHolding:apple];
    [myStockPortfolio addStockHolding:euroRiverView];
    [myStockPortfolio addStockHolding:google];
    [myStockPortfolio addStockHolding:euroGoogle];
    [myStockPortfolio addStockHolding:euroApple];
    
     
    NSLog(@"CURRENT PORTFOLIO VALUE: $%.2f", [myStockPortfolio currentValue]);
    NSLog(@"NUMBER OF STOCKS: %d", [myStockPortfolio arrayCount]);
    
    [myStockPortfolio displayPortfolio];
    
    
}
return 0;

}[/code]