Gold Challenge Solution


#1

I’m not quite sure if this is what the authors had in mind, but it seems to work! Each container tallies up the value of its contents and adds its own value (the value of the container when it is empty). A second container can be placed inside the first and its contents display correctly when printed to the console. When tallying up a container’s total value, I used the method “respondsToSelector” to check whether an item was a BNRItem or a BNRContainer. Only BNRContainers have the method “totalContainerValue.” I’m sure there’s an even better way to do this…would love to know what it is!

BNRContainer.h

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

@interface BNRContainer : BNRItem

@property (nonatomic) NSMutableArray *containerItems;
@property (nonatomic, copy) NSString *containerName;

- (instancetype)initWithContainerName:(NSString *)name containerValue:(int)value;
- (instancetype)initWithContainerName:(NSString *)name;
- (int)totalContainerValue;
- (void)addItemToContainer:(id)item;

@end

BNRContainer.m

#import "BNRContainer.h"
#import "BNRItem.h"

@implementation BNRContainer


// Designated initializer
- (instancetype)initWithContainerName:(NSString *)name containerValue:(int)value
{
    self = [super init];
    if (self) {
        _containerName = name;
        _valueInDollars = value;
    }
    return self;
}

- (instancetype)initWithContainerName:(NSString *)name
{
    return [self initWithContainerName:name containerValue:0];
}

- (instancetype)init
{
    return [self initWithContainerName:@"Unknown"];
}


- (int)totalContainerValue
{
    int sum = 0;
    for (id item in self.containerItems) {
        
        // If the item is a container, add its totalContainerValue
        if ([item respondsToSelector:@selector(totalContainerValue)])
        {
            int total = [item totalContainerValue];
            sum += total;
        }
        
        
        // If the item is a BNRItem, add its valueInDollars
        if (![item respondsToSelector:@selector(totalContainerValue)]) {
            sum += [item valueInDollars];
        }
    }
    
    sum += self.valueInDollars;
    return sum;
}

- (void)addItemToContainer:(id)item
{
    // Check to see if containerItems is nil
    if (!self.containerItems)
    {
        self.containerItems = [[NSMutableArray alloc] init];
    }
    
    [self.containerItems addObject:item];
}

// Overriding the BNRItem description
- (NSString *)description
{
    NSString *descriptionString = [[NSString alloc] initWithFormat:@"Name: %@, Worth: %d, Total Value: %d, Contents: %@", self.containerName, self.valueInDollars, self.totalContainerValue, self.containerItems];
    
    return descriptionString;
}


@end

main.m

@import Foundation;
#import "BNRItem.h"
#import "BNRContainer.h"

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

    @autoreleasepool {
        
        // Create a primary container
        BNRContainer *container = [[BNRContainer alloc] initWithContainerName:@"Furniture" containerValue:200];
        
        // Load primary container with BNRItems
        for (int i = 0; i < 10; i++) {
            BNRItem *item = [BNRItem randomItem];
            [container addItemToContainer:item];
        }

        // Create a second container to be placed inside the first
        BNRContainer *secondContainer = [[BNRContainer alloc] initWithContainerName:@"Electronics" containerValue:100];
        
        // Add an item to the second container
        BNRItem *newItem = [BNRItem randomItem];
        [secondContainer addItemToContainer:newItem];
        
        // Add the second container to the first
        [container addItemToContainer:secondContainer];
                
        
        NSLog(@"%@", container);
    }
    return 0;
}

#2

As another idea, I went with the approach of overriding valueInDollars in BNRContainer to return the total. For example:

- (int)valueInDollars
{
    int totalValueInDollars = _valueInDollars;

    for (BNRItem *item in self.containerItems) {
        totalValueInDollars += item.valueInDollars;
    }

    return totalValueInDollars;
}

#3

Wow, I’m feeling like an idiot after reading this. I’m having a hard time just getting started on this challenge!


#4

I also have no clue if I did understand the challenge right or not. Anyways here is my solution.
I added a view methods to work with the BNRContainer like with a NSMutableArray.

BNRContainer.h

#import "BNRItem.h"

@interface BNRContainer : BNRItem
{
    @private NSMutableArray *_containerArray;
}

/* Designated Initializer */

- (instancetype)initWithItemName:(NSString *)name valueInDollars:(int)value;

/* getter for the array */

- (NSMutableArray *)containerArray;

/* some methods like in NSArray */

- (NSUInteger)count;
- (id)objectAtIndex:(NSUInteger)index;

/* some methods like in NSMutableArray */

- (void)addObject:(id)anObject;
- (void)insertObject:(id)anObject atIndex:(NSUInteger)index;
- (void)removeLastObject;
- (void)removeObjectAtIndex:(NSUInteger)index;
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;

/* get the total value of the container */

- (int)totalValueInDollars;

/* command line output - overridden */

- (NSString *)description;

@end

BNRContainer.m

#import "BNRContainer.h"

@implementation BNRContainer

#pragma mark - Initializer

/* Designated Initializer */

- (instancetype)initWithItemName:(NSString *)name valueInDollars:(int)value
{
    self = [super initWithItemName:name valueInDollars:value serialNumber:nil];
    
    if (self) {
        _containerArray = [[NSMutableArray alloc] init];
    }
    return self;
}

/* Overridden Initializer of the super class to prevent any exceptions */

- (instancetype)initWithItemName:(NSString *)name valueInDollars:(int)value serialNumber:(NSString *)sNumber
{
    return [self initWithItemName:name valueInDollars:value];
}

- (instancetype)initWithItemName:(NSString *)name serialNumber:(NSString *)sNumber
{
    return [self initWithItemName:name];
}

- (instancetype)initWithItemName:(NSString *)name
{
    return [self initWithItemName:name valueInDollars:0];
}

- (instancetype)init
{
    return [self initWithItemName:@"Unknown"];
}

#pragma mark -
#pragma mark - Other Methods

/* getter for the Array */

- (NSMutableArray *)containerArray
{
    return _containerArray;
}

/* some methods like in NSArray */

- (NSUInteger)count
{
    return [_containerArray count];
}

- (id)objectAtIndex:(NSUInteger)index
{
    return [_containerArray objectAtIndex:index];
}

/* some methods like in NSMutableArray */

-(void)addObject:(id)anObject
{
    /* prevent adding other objects to the array */
    if ([anObject isKindOfClass:[BNRContainer class]] || [anObject isKindOfClass:[BNRItem class]]) {
        [_containerArray addObject];
    }
}

- (void)insertObject:(id)anObject atIndex:(NSUInteger)index
{
    /* prevent adding other objects to the array */
    if ([anObject isKindOfClass:[BNRContainer class]] || [anObject isKindOfClass:[BNRItem class]]) {
        [_containerArray insertObject:anObject atIndex:index];
    }
}

- (void)removeLastObject
{
    [_containerArray removeLastObject];
}

- (void)removeObjectAtIndex:(NSUInteger)index
{
    [_containerArray removeObjectAtIndex:index];
}

- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject
{
    /* prevent adding other objects to the array */
    if ([anObject isKindOfClass:[BNRContainer class]] || [anObject isKindOfClass:[BNRItem class]]) {
        [_containerArray replaceObjectAtIndex:index withObject];
    }
}

- (int)totalValueInDollars;
{
    int totalValueInDollars = _valueInDollars;
    
    for (id item in self.containerArray) {
        
        if ([item isMemberOfClass:[BNRContainer class]]) {
            /* recursion */
            totalValueInDollars += [item totalValueInDollars];
        } else {
            totalValueInDollars += [item valueInDollars];
        }
    }
    
    return totalValueInDollars;
}

- (NSString *)description
{
    NSString *decriptionString = [[NSString alloc] initWithFormat:@"Container: '%@' Worth $%d, recorded on %@\n%@",
                                  self.itemName,
                                  self.totalValueInDollars,
                                  self.dateCreated,
                                  self.containerArray];
    return decriptionString;
}

@end

main.m

#import <Foundation/Foundation.h>
#import "BNRItem.h"
#import "BNRContainer.h"

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        
        NSMutableArray *items = [[NSMutableArray alloc] init];
        for (int i = 0; i < 10; i++) {
            BNRItem *item = [BNRItem randomItem];
            [items addObject:item];
        }
      
        for (NSString *item in items) {
            NSLog(@"%@", item);
        }
        
        BNRContainer *firstContainer = [[BNRContainer alloc] initWithItemName:@"Gold Item" valueInDollars:50];
        
        BNRContainer *secondContainer = [[BNRContainer alloc] initWithItemName:@"Platinum Item" valueInDollars:100];
        
        for (int i = 0; i < 5; i++) {
            [secondContainer addObject:items[i]];
        }
        
        [firstContainer addObject:secondContainer];
        
        for (int i = 5; i < 10; i++) {
            [firstContainer addObject:items[i]];
        }
        
        NSLog(@"%@",[firstContainer objectAtIndex:0]);
        
        NSLog(@"%@",firstContainer);

        firstContainer = nil;
        secondContainer = nil;
        items = nil;
        
    }
    return 0;
}