Chapter 24 challenge return NSArray of top three stocks


#1

can someone please help me with the chapter 24 challenge that requires you to add a method to the BNRPortfolio class that returns an NSArray of only the top three most valuable stock holdings, sorted by current value in dollars? Heres what I have for BNRPortfolio.h:

#import <Foundation/Foundation.h>
// use @class so we can declare that this portfolio class will access the
// 'valueInDollars' instance variable from the BNRStockHolding class
@class BNRStockHolding;

@interface BNRPortfolio : NSObject

// explicitly declare a method of NSMutableArray to be able to manipulate
// all instances of BNRStockHolding within
// now removing this declaration and making it a class extension in BNRPortfolio.m file
//{
    //NSMutableArray *_holdings;
//}

@property (nonatomic, copy) NSArray *holdings;
@property (nonatomic, copy) NSArray *mostValuableHoldings;

- (float)totalValue;
- (void)addHolding:(BNRStockHolding *)h;
- (void)removeHolding:(BNRStockHolding *)r;

@end

and for the .m file:

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

@interface BNRPortfolio ()

{
    NSMutableArray *_holdings;
    NSMutableArray *_mostValuableStocks;
}

@end

@implementation BNRPortfolio

// here we are manually defining how to set the holding array value declared
// as a property in the header file using the _holding mutable array declared separately
// as a means of manipulation behind the scenes before returning a copy of it in the the
// form of an immutable NSArray
- (void)setHoldings:(NSArray *)s
{
    _holdings = [s mutableCopy];
}

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

- (NSArray *)mostValuableStocks;
{
    NSSortDescriptor *highToLow = [NSSortDescriptor sortDescriptorWithKey:@"valueInDollars" ascending:NO];
    [_holdings sortUsingDescriptors: @[highToLow]];
    for (int i = 0; i < 3; i++) {
        for (BNRStockHolding *m in _holdings) {
            [_mostValuableStocks addObject:m];
            break;
        }
    }
    return [_mostValuableStocks copy];
}

- (void)addHolding:(BNRStockHolding *)h
{
    // is the holdings array nil?
    if (!_holdings) {
        // create the array
        _holdings = [[NSMutableArray alloc] init];
    }
    // add the holding in to the holdings array
    [_holdings addObject:h];
}

// describe how removeHolding works
- (void)removeHolding:(BNRStockHolding *)r
{
    if (r) {
        [_holdings removeObject:r];
    }
}

- (float)totalValue
{
    // add the currentValue values of all holdings in the holdings array by iterating through
    // it and returning the sum
    float sum = 0;
    for (BNRStockHolding *h in _holdings) {
        sum += [h valueInDollars];
    }
    return sum;
}

// change the description property to return an NSString with the total value of the portfolio
- (NSString *)description
{
    return [NSString stringWithFormat:@"<stock portfolio with a total value of %.2f>", self.totalValue];
}


@end

and main:

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

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

    @autoreleasepool {
        
        
        BNRPortfolio *domesticStocks = [[BNRPortfolio alloc] init];
        
        for (int i = 0; i < 10; i++) {
            BNRStockHolding *appl = [[BNRStockHolding alloc] init];
            
            appl.purchaseSharePrice = 100 - i + 10;
            appl.currentSharePrice = 490 - i * 2;
            appl.numberOfShares = i * i;
            appl.stockName = [NSString stringWithFormat:@"APPL%d", i];
            
            // add the stock into the portfolio
            [domesticStocks addHolding:appl];
        }
        
        NSLog(@"%@", domesticStocks);
        
        NSArray *mVS = [domesticStocks mostValuableHoldings];
        
        NSLog(@"%@", mVS);

    }
    return 0;
}

please help. I want to fully understand what I’m doing wrong and why your solution will work. thanks in advance guys!


#2

Ok, I figured it out thanks to stack overflow. I simply wasn’t creating my “_mostValuableHoldings” (changed from _mostValuableStocks) mutable array. after adding some code that, like the code provided earlier in the book, checks to see if the mutable array was initiated and initiates it if not, I realized that my iteration tool to add the top three stocks to the array was also wrong. I was adding in the top (most valuable stock of all) three times instead of adding in the top three most valuable stocks. below is the corrected code from the BNRPortfolio.m file. I only included the portion I changed. I hope this helps someone else who’s stuck.

- (NSArray *)mostValuableHoldings
{
    if (!_mostValuableHoldings) {
        _mostValuableHoldings = [[NSMutableArray alloc] init];
    }
    NSSortDescriptor *highToLow = [NSSortDescriptor sortDescriptorWithKey:@"valueInDollars" ascending:NO];
    [_holdings sortUsingDescriptors: @[highToLow]];
        for (int i = 0; i < 3; i++) {
            [_mostValuableHoldings addObject:_holdings[i]];
        }
    return [_mostValuableHoldings copy];
}

#3

Just curious, why do you do use "copy" rather than just "return _mostValuableStocks"? I did mine differently where I created an NSMutableArray and after I was done adding the array, I returned that object.

Just curious, why do you do use “copy” rather than just “return _mostValuableStocks”? I did mine differently where I created an NSMutableArray and after I was done adding the array, I returned that object.