Challenge: Stocks (Solution)

So in a lot of the older posts I hear that it is impractical to access the stock you wish to remove via the index when creating your method. However I tried nearly everything I could think of an was not having any success trying to remove a stock via the ticker label or name. Anyways, here is my solution when removing by index.

JSStockHolding.h

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

@interface JSStockHolding : NSObject

@property (nonatomic) float purchaseSharePrice;
@property (nonatomic) int numberShares;
@property (nonatomic) float currentSharePrice;
@property (nonatomic, copy) NSString *companyName;
@property (nonatomic, copy) NSString *tickerLabel;

  • (float)costDollars; // purchaseSharePrice * numberShares
  • (float)valueDollars; // currentSharePrice * numberShares

@end[/code]

JSStockHolding.m

[code]#import “JSStockHolding.h”

@implementation JSStockHolding

  • (float)costDollars
    {
    return self.purchaseSharePrice * self.numberShares;
    }

  • (float)valueDollars
    {
    return self.currentSharePrice * self.numberShares;
    }

  • (NSString *)description
    {
    NSString *descriptionMethod = [NSString stringWithFormat:@“You paid %.2f for %d shares in %@ (%@), valued at %.2f”, self.costDollars, self.numberShares, self.companyName, self.tickerLabel, self.valueDollars];
    return descriptionMethod;
    }

@end[/code]

JSForeignStockHolding.h

[code]#import “JSStockHolding.h”

@interface JSForeignStockHolding : JSStockHolding

@property (nonatomic) float conversionRate;

@end[/code]

JSForeignStockHolding.m

[code]#import “JSForeignStockHolding.h”

@implementation JSForeignStockHolding

  • (float)costDollars
    {
    return self.purchaseSharePrice * self.numberShares * self.conversionRate;
    }

  • (float)valueDollars
    {
    return self.currentSharePrice * self.numberShares * self.conversionRate;
    }

  • (NSString *)description
    {
    NSString *descriptionMethod = [NSString stringWithFormat:@“You paid %.2f for %d shares in %@ (%@), valued at %.2f (CR:%.2f)”, self.costDollars, self.numberShares, self.companyName, self.tickerLabel, self.valueDollars, self.conversionRate];
    return descriptionMethod;
    }

@end[/code]

JSPortfolio.h

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

@interface JSPortfolio : NSObject

@property (nonatomic, copy) NSArray *stocks;

  • (void)addStock:(JSStockHolding *)stock;

  • (void)removeStockAtIndex:(int)index;

  • (float)portfolioValue;

  • (float)totalCost;

@end[/code]

JSPortfolio.m

[code]#import “JSPortfolio.h”

@interface JSPortfolio()

{
NSMutableArray *_stocks;
}

@end

@implementation JSPortfolio

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

  • (NSArray *)stocks
    {
    return [_stocks mutableCopy];
    }

  • (void)addStock:(JSStockHolding *)stock
    {
    // if (portfolio array does not exist)
    if (!_stocks) {
    _stocks = [[NSMutableArray alloc] init];
    }
    [_stocks addObject:stock];
    }

  • (void)removeStockAtIndex:(int)index
    {
    if ([_stocks objectAtIndex:index]) {
    [_stocks removeObjectAtIndex:index];
    NSLog(@“Stock has successfully been removed from your portfolio.\n”);
    }
    }

  • (float)portfolioValue
    {
    float sum = 0;
    for (JSStockHolding *stock in _stocks) {
    sum += [stock valueDollars];
    }
    return sum;
    }

  • (float)totalCost
    {
    float sum = 0;
    for (JSStockHolding *stock in _stocks) {
    sum += [stock costDollars];
    }
    return sum;
    }

  • (NSString *)description
    {
    NSString *descriptionMethod = [NSString stringWithFormat:@"%@\nYour portfolio cost %.2f and is valued at %.2f", self.stocks, self.totalCost, self.portfolioValue];
    return descriptionMethod;
    }

@end[/code]

Main.m

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

int main(int argc, const char * argv[]) {
@autoreleasepool {
JSPortfolio *financialPortfolio = [[JSPortfolio alloc] init];

    //  Arrays of names generated for later assignment to stock objects
    NSArray *localNames = @[@"Apple", @"Chrysler", @"Microsoft", @"Netflix"];
    NSArray *foreignNames = @[@"Izuzu", @"Toyota", @"Toshiba", @"Fujitsu"];
    
    for (int i = 0; i < [localNames count]; i++) {
        //  Dont worry about the math, it just creates really random numbers
        float randomPurchasePrice = 2.30 + i * (arc4random() % 3);
        float randomCurrentPrice = 4.50 + i * (arc4random() % 2);
        int randomNumberShares = 15 + i * (arc4random() % 20);
        
        //  ---- "JSStockHolding" object ----
        localStock = [[JSStockHolding alloc] init];
        
        NSString *localCompany = [localNames objectAtIndex:i];
        localStock.companyName = localCompany;
        
        localStock.purchaseSharePrice = randomPurchasePrice;
        localStock.currentSharePrice = randomCurrentPrice;
        localStock.numberShares = randomNumberShares;
        
        NSArray *tickerLabels = @[@"ABC", @"DEF", @"GHI", @"JKL"];
        localStock.tickerLabel = [tickerLabels objectAtIndex:i];
        
        [financialPortfolio addStock:localStock];
        
        //  ---- "JSForeignStockHolding" object ----
        foreignStock = [[JSForeignStockHolding alloc] init];
        
        NSString *foreignCompany = [foreignNames objectAtIndex:i];
        foreignStock.companyName = foreignCompany;
        
        foreignStock.purchaseSharePrice = randomPurchasePrice;
        foreignStock.currentSharePrice = randomCurrentPrice;
        foreignStock.numberShares = randomNumberShares;
        foreignStock.conversionRate = 0.50 + (0.15 * i);
        
        NSArray *fTickers = @[@"MNO", @"PQR", @"STU", @"VWX"];
        foreignStock.tickerLabel = [fTickers objectAtIndex:i];
        
        [financialPortfolio addStock:foreignStock];
    }  //  End @ for-loop
    
    //  Remove one stock object from portfolio array at specified index 
    [financialPortfolio removeStockAtIndex:2];
    
    //  Print contents of portfolio
    NSLog(@"%@", financialPortfolio);
}
return 0;

}[/code]

Output

[quote]Stock has successfully been removed from your portfolio.
(
“You paid $34.50 for 15 shares in Apple (ABC), valued at $67.50”,
“You paid $17.25 for 15 shares in Izuzu (MNO), valued at $33.75 (CR:0.50)”,
“You paid $89.44 for 32 shares in Toyota (PQR), valued at $93.60 (CR:0.65)”,
“You paid $89.70 for 39 shares in Microsoft (GHI), valued at $253.50”,
“You paid $71.76 for 39 shares in Toshiba (STU), valued at $202.80 (CR:0.80)”,
“You paid $224.10 for 27 shares in Netflix (JKL), valued at $121.50”,
“You paid $212.90 for 27 shares in Fujitsu (VWX), valued at $115.42 (CR:0.95)”
)
Your portfolio cost $739.65 and is valued at $888.08[/quote]

The farthest I can come in terms of removing a stock by name is this. But note that for some reason it only works for the last regularStock and foreignStock name. For any other of the stock names in the portfolio array, it prints the entire portfolio with no objects removed. I thought I understood why this was, because of how unique that pattern is. However I don’t think I can figure it out now. Anyways here are the changes and method used from above to do this. This shows one object not being removed while the other correctly being removed.

JSPortfolio.h

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

@interface JSPortfolio : NSObject

@property (nonatomic, copy) NSArray *stocks;

  • (void)addStock:(JSStockHolding *)stock;

  • (void)removeStock:(JSStockHolding *)stock withName:(NSString *)name;

  • (float)portfolioValue;

  • (float)totalCost;

@end[/code]

JSPortfolio.m

[code]#import “JSPortfolio.h”

@interface JSPortfolio()

{
NSMutableArray *_stocks;
}

@end

@implementation JSPortfolio

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

  • (NSArray *)stocks
    {
    return [_stocks mutableCopy];
    }

  • (void)addStock:(JSStockHolding *)stock
    {
    // if (portfolio array does not exist)
    if (!_stocks) {
    _stocks = [[NSMutableArray alloc] init];
    }
    [_stocks addObject:stock];
    }

  • (void)removeStock:(JSStockHolding *)stock withName:(NSString *)name
    {
    for (int i = 0; i < [self.stocks count]; i++) {
    if (stock.companyName == name) {
    [_stocks removeObject:stock];
    // Log for clarity purposes
    NSLog(@“Removing %@ from portfolio.\n”, stock.companyName);
    break; // End loop once name found
    }
    }
    }

  • (float)portfolioValue
    {
    float sum = 0;
    for (JSStockHolding *stock in _stocks) {
    sum += [stock valueDollars];
    }
    return sum;
    }

  • (float)totalCost
    {
    float sum = 0;
    for (JSStockHolding *stock in _stocks) {
    sum += [stock costDollars];
    }
    return sum;
    }

  • (NSString *)description
    {
    NSString *descriptionMethod = [NSString stringWithFormat:@"%@\nYour portfolio cost %.2f and is valued at %.2f", self.stocks, self.totalCost, self.portfolioValue];
    return descriptionMethod;
    }

@end[/code]

Main.m

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

int main(int argc, const char * argv[]) {
@autoreleasepool {
JSPortfolio *financialPortfolio = [[JSPortfolio alloc] init];

    //  Declared outside of loop such that "removeStock" method will work
    JSStockHolding *localStock;
    JSForeignStockHolding *foreignStock;

    //  Arrays of names generated for later assignment to stock objects
    NSArray *localNames = @[@"Apple", @"Chrysler", @"Microsoft", @"Netflix"];
    NSArray *foreignNames = @[@"Izuzu", @"Toyota", @"Toshiba", @"Fujitsu"];
    
    for (int i = 0; i < [localNames count]; i++) {
        //  Dont worry about the math, it just creates really random numbers
        float randomPurchasePrice = 2.30 + i * (arc4random() % 3);
        float randomSharePrice = 4.50 + i * (arc4random() % 2);
        int randomNumberShares = 15 + i * (arc4random() % 25);
        
        //  ---- "JSStockHolding" object ----
        localStock = [[JSStockHolding alloc] init];
        
        NSString *localCompany = [localNames objectAtIndex:i];
        localStock.companyName = localCompany;
        
        localStock.purchaseSharePrice = randomPurchasePrice;
        localStock.currentSharePrice = randomSharePrice;
        localStock.numberShares = randomNumberShares;
        
        NSArray *tickerLabels = @[@"ABC", @"DEF", @"GHI", @"JKL"];
        localStock.tickerLabel = [tickerLabels objectAtIndex:i];
        
        [financialPortfolio addStock:localStock];
        
        //  ---- "JSForeignStockHolding" object ----
        foreignStock = [[JSForeignStockHolding alloc] init];
        
        NSString *foreignCompany = [foreignNames objectAtIndex:i];
        foreignStock.companyName = foreignCompany;
        
        foreignStock.purchaseSharePrice = randomPurchasePrice;
        foreignStock.currentSharePrice = randomSharePrice;
        foreignStock.numberShares = randomNumberShares;
        foreignStock.conversionRate = 0.50 + (0.15 * i);
        
        NSArray *fTickers = @[@"MNO", @"PQR", @"STU", @"VWX"];
        foreignStock.tickerLabel = [fTickers objectAtIndex:i];
        
        [financialPortfolio addStock:foreignStock];
    }
    
    //  Remove one localStock and one foreignStock from portfolio
    [financialPortfolio removeStock:localStock
                         withName:@"Apple"];
    [financialPortfolio removeStock:foreignStock
                         withName:@"Fujitsu"];
    
    //  Print contents of portfolio
    NSLog(@"%@", financialPortfolio);
}
return 0;

}[/code]

Output

[quote]Removing Fujitsu from portfolio.
(
“You paid $34.50 for 15 shares in Apple (ABC), valued at $67.50”,
“You paid $17.25 for 15 shares in Izuzu (MNO), valued at $33.75 (CR:0.50)”,
“You paid $52.90 for 23 shares in Chrysler (DEF), valued at $103.50”,
“You paid $34.38 for 23 shares in Toyota (PQR), valued at $67.27 (CR:0.65)”,
“You paid $64.50 for 15 shares in Microsoft (GHI), valued at $67.50”,
“You paid $51.60 for 15 shares in Toshiba (STU), valued at $54.00 (CR:0.80)”,
“You paid $95.40 for 18 shares in Netflix (JKL), valued at $135.00”
)
Your portfolio cost $350.54 and is valued at $528.53[/quote]

EDIT: Now that I look at it again, I think it has to do with the fact that in Main.m I first create pointers for the local and foreign stock classes, yet within the loop perhaps this is doing something different which is interfering with accessing the correct object when attempting to remove it from outside of the loop?