Challenges

This one had me going for a while. Kept irritating me because no matter what I did it would only return the memory address instead of the stock name or value!!! lol I let the project sit for 2 days, went back a few chapters to go over it all and make sure I didn’t make any mistakes and saw the “descriptors and %@” section to realize I was returning the default NSObject descriptor! After about 4 days of research on the code that I wrote in 3 different ways, all of which would have worked, it was a single line in the BNRStockHoldings class lol, but at least I will remember this from now on. See the following for my project:

note, I didn’t create BNRForeignStockHoldings. I felt it wasn’t really needed so I created conversionRate in BNREmployee, and added an if statement to determine if it needed to be converted. Basically, if conversionRate is empty, calculate valueInDollar/costInDollars, else if it is not empty (IE contains a value), add the exchange rate to the equation.

Main.m

[code]//
// main.m
// Stocks
//
// Created by Matthew Raby on 8/18/14.
// Copyright © 2014 Big Nerd Ranch. All rights reserved.
//

#import <Foundation/Foundation.h>
#import “BNRPortfolio.h”
#import “BNRPortfolio.h”

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

@autoreleasepool {
    
    // Create BNRPortfolio object to store all the stocks
    BNRPortfolio *portfolio = [[BNRPortfolio alloc] init];
    
    // create BNRStockHolding instances, assign values, and add to portfolio
    
    BNRStockHolding *pike     = [[BNRStockHolding alloc] init];
    BNRStockHolding *starrett = [[BNRStockHolding alloc] init];
    BNRStockHolding *facebook = [[BNRStockHolding alloc] init];
    BNRStockHolding *chinaTech = [[BNRStockHolding alloc] init];
    BNRStockHolding *indiaComp = [[BNRStockHolding alloc] init];
    BNRStockHolding *poorCountry = [[BNRStockHolding alloc] init];
    
    pike.purchaseSharePrice = 8.30;
    pike.currentSharePrice = 11.82;
    pike.numberOfShares = 50;
    pike.stockName = @"PIKE";
    [portfolio addToPortfolio:pike];
    
    starrett.purchaseSharePrice = 8.6;
    starrett.currentSharePrice = 15.54;
    starrett.numberOfShares = 200;
    starrett.stockName = @"SCX";
    [portfolio addToPortfolio];
    
    facebook.purchaseSharePrice = 60;
    facebook.currentSharePrice = 73.63;
    facebook.numberOfShares = 100;
    facebook.stockName = @"FB";
    [portfolio addToPortfolio];
    
    chinaTech.purchaseSharePrice = 800;
    chinaTech.currentSharePrice = 1000;
    chinaTech.numberOfShares = 50;
    chinaTech.stockName = @"CTECH";
    chinaTech.conversionRate = 0.0689;
    [portfolio addToPortfolio:chinaTech];
    
    indiaComp.purchaseSharePrice = 15677.8;
    indiaComp.currentSharePrice = 22568.7;
    indiaComp.numberOfShares = 10;
    indiaComp.stockName = @"ICOMP";
    indiaComp.conversionRate = 0.00327;
    [portfolio addToPortfolio:indiaComp];
    
    poorCountry.purchaseSharePrice = 200.8;
    poorCountry.currentSharePrice = 2283.2;
    poorCountry.numberOfShares = 30;
    poorCountry.stockName = @"PCNTR";
    poorCountry.conversionRate = 0.000843;
    [portfolio addToPortfolio:poorCountry];
    
    // Iterate through the array and print the stocks
    
    for (BNRStockHolding *i in portfolio.holdings) {
        // declare local variables
        float purchasedAt = i.costInDollars;
        float currentValue = i.valueInDollars;
        float netValue = i.netValueInDollars;
        NSString *name = i.stockName;
        NSLog(@"\nStock: %@\nPrice Purchased: %.2f\nCurrent Value: %.2f\nProfit: %.2f\n", name, purchasedAt, currentValue, netValue);
    }
    
    // Print the holdings in alphabetical order
    NSLog(@"Holdings sorted by symbol: %@", [portfolio stockSortedABC]);
    // print the top 3 valued holdings
    NSLog(@"Top 3 most valuable holdings: %@", [portfolio topThreeHoldings]);
    // cleanup holdings
    portfolio = nil;
    
    
    /* Commenting out previous challenge code not needed for this challenge, to keep for future reference
     
     
    NSLog(@"The total value of all stocks is %.2f", [portfolio totalValue]);
    NSLog(@"The value of portfolio[3] is %.2f", chinaTech.valueInDollars);
    //remove chinaTech
    [portfolio removeFromPortfolio:3];
    // should be the total value minus chinaTech
    NSLog(@"The total after removing portfolio[3] is %@", portfolio);
    */
    
}
return 0;

}
[/code]

BNRStockHoldings.h

[code]//
// BNRStockHolding.h
// Stocks
//
// Created by Matthew Raby on 8/18/14.
// Copyright © 2014 Big Nerd Ranch. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface BNRStockHolding : NSObject

// Declare properties
@property (nonatomic) float purchaseSharePrice;
@property (nonatomic) float currentSharePrice;
@property (nonatomic) int numberOfShares;
@property (nonatomic) NSString *stockName;
@property (nonatomic) float conversionRate;

// Declare the instance methods

  • (float)costInDollars; // purchaseSharePrice * numberOfShares
  • (float)valueInDollars; // currentSharePrice * numberOfShares
  • (float)netValueInDollars; // valueInDollars - costInDollars

@end[/code]

BNRStockHoldings.m

[code]//
// BNRStockHolding.m
// Stocks
//
// Created by Matthew Raby on 8/18/14.
// Copyright © 2014 Big Nerd Ranch. All rights reserved.
//

#import “BNRStockHolding.h”

@implementation BNRStockHolding

// create method to calculate cost to purchase stock, include conversion if non-US currency

  • (float)costInDollars {
    if (!_conversionRate) {

    float cost = self.purchaseSharePrice;
    return cost * self.numberOfShares;

    } else {

      float cost = self.purchaseSharePrice;
      float num = self.numberOfShares;
      return cost * num * self.conversionRate;
    

    }
    }

// create method to calculate the current value of the stock, include conversion if non-US currency

  • (float)valueInDollars {
    if(!_conversionRate){

      float val = self.currentSharePrice;
      return val * self.numberOfShares;
    

    }else{

      float val = self.currentSharePrice;
      float num = self.numberOfShares;
      return val * num * self.conversionRate;
    

    }
    }

// calculate the profit

  • (float)netValueInDollars {

    return self.valueInDollars - self.costInDollars;
    }

  • (void)addSelfToArray:(NSMutableArray *)array
    {
    [array addObject:self];
    }

// The default description method of NSObject returns the memory location when using %@ in NSLog
// Overwrite the description method to return a more specific message, for this project the stock name

  • (NSString *)description
    {
    return [NSString stringWithFormat:@"<BNRStockHoldings: %@, valued at %.2f>", self.stockName, self.valueInDollars];
    }

@end[/code]

BNRPortfolio.h

[code]//
// BNRPortfolio.h
// Stocks
//
// Created by Matthew Raby on 8/18/14.
// Copyright © 2014 Big Nerd Ranch. All rights reserved.
//

#import <Foundation/Foundation.h>
#import “BNRStockHolding.h”

@interface BNRPortfolio : NSObject

@property (nonatomic, copy) NSArray *holdings;

  • (void)addToPortfolio:(BNRStockHolding *)a;
  • (void)removeFromPortfolio:(unsigned int)i;
  • (float)totalValue;
  • (NSArray *)topThreeHoldings;
  • (NSArray *)stockSortedABC;

@end
[/code]

BNRPortfolio.m

[code]//
// BNRPortfolio.m
// Stocks
//
// Created by Matthew Raby on 8/18/14.
// Copyright © 2014 Big Nerd Ranch. All rights reserved.
//

#import “BNRPortfolio.h”
@interface BNRPortfolio ()
{
NSMutableArray *_holdings;
}

@end
@implementation BNRPortfolio

// setter method for - @property (nonatomic, copy) NSArray *portfolio;

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

// getter method for - @property (nonatomic, copy) NSArray *portfolio;

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

  • (void)addToPortfolio:(BNRStockHolding *)a
    {
    if (!_holdings) {
    _holdings = [[NSMutableArray alloc] init];
    }
    [_holdings addObject:a];
    }
    -(void)removeFromPortfolio: (unsigned int)i
    {
    [_holdings removeObjectAtIndex:i];
    }

  • (NSArray *)topThreeHoldings
    {
    NSSortDescriptor *sortValue = [NSSortDescriptor sortDescriptorWithKey:@“valueInDollars” ascending:NO];
    NSMutableArray *sortVID= [[NSMutableArray alloc] init];
    sortVID = _holdings;
    [sortVID sortUsingDescriptors:@[sortValue]];

    //noticed someone use the NSMakeRange to do this instead of calling each individually, I liked it better
    return [sortVID subarrayWithRange:NSMakeRange(0, 2)];
    //return @[sortVID[0], sortVID[1], sortVID[2]];
    }

  • (NSArray *)stockSortedABC
    {
    NSSortDescriptor *sortABC = [NSSortDescriptor sortDescriptorWithKey:@“stockName” ascending:YES];
    NSMutableArray *sortedArray = [[NSMutableArray alloc] init];
    sortedArray = _holdings;
    [sortedArray sortUsingDescriptors:@[sortABC]];

    return sortedArray;
    }

  • (float)totalValue
    {
    float sum = 0.0;
    for (BNRStockHolding a in _holdings)
    {
    sum += a.valueInDollars;
    }
    return sum;
    }
    /

  • (NSString *)description
    {
    return [NSString stringWithFormat:@“The total value of my portfolio is %.2f”, self.totalValue];
    }
    */
    @end[/code]

I noticed a small flaw in your code that I wanted to point out.

In your topThreeHoldings method for BNRPortfolio.m you need to write:

return [sortVID subarrayWithRange:NSMakeRange(0, 3)];

There reason being NSMakeRange( location, length).

At the moment your code only prints out the top two stocks.