Golden Challenge: recursive description method


#1

Hi all, following is my implementation. The focus is at the description method of BNRContainer Class

One of the requirement from the Authors is that any container instance lives within a given container instance. There will be containerA within containerB which again within containerC and so on. So the description and the value summation has to be recursive to make the method simple.

Following are my codes:
BNRItem.h

//
//  BNRItem.h
//  RandomPossessions
//
//  Created by VR2VNA on 2/20/13.
//  Copyright (c) 2013 __MyCompanyName__. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface BNRItem : NSObject
{
    NSString *itemName;
    NSString *serialNumber;
    int valueInDollars;
    NSDate *dateCreated;
}

+(id)randomItem;

-(id)initWithItemName:(NSString *)name
      setSerialNumber:(NSString *)serial;

-(id)initWithItemName:(NSString *)name 
       valueInDollars:(int)value 
         serialNumber:(NSString *)serial;

-(void)setItemName:(NSString *)str;
-(NSString *)itemName;

-(void)setSerialNumber:(NSString *)str;
-(NSString *)serialNumber;

-(void)setValueInDollars:(int)i;
-(int)valueInDollars;

-(NSDate *)dateCreated;

-(NSString *)description;

@end

BNRItem.m

//
//  BNRItem.m
//  RandomPossessions
//
//  Created by VR2VNA on 2/20/13.
//  Copyright (c) 2013 __MyCompanyName__. All rights reserved.
//

#import "BNRItem.h"

@implementation BNRItem

+(id)randomItem
{
    NSArray *randomAdjectiveList = [NSArray arrayWithObjects:@"Fluffy", @"Rusty", @"Shinny", nil];
    NSArray *randomNounList = [NSArray arrayWithObjects:@"Bear", @"Spock", @"Max", nil];
    
    NSInteger adjectiveIndex = rand() % [randomAdjectiveList count];
    NSInteger nounIndex = rand() % [randomNounList count];
    
    NSString *randomName = [NSString stringWithFormat:@"%@ %@",[randomAdjectiveList objectAtIndex:adjectiveIndex], [randomNounList objectAtIndex:nounIndex]];
    
    int randomValue = rand() % 100;
    
    NSString *randomSerial = [NSString stringWithFormat:@"%c%c%c%c%c",
                              '0' + rand() % 10,
                              'A' + rand() % 26,
                              '0' + rand() % 10,
                              'A' + rand() % 26,
                              '0' + rand() % 10];
                                                                        
    
    BNRItem *newItem = [[self alloc] initWithItemName:randomName valueInDollars:randomValue serialNumber:randomSerial];
    
    return newItem;
    
}


-(id)initWithItemName:(NSString *)name 
       valueInDollars:(int)value 
         serialNumber:(NSString *)serial
{
    self = [super init];
    
    [self setItemName:name];
    [self setValueInDollars:value];
    [self setSerialNumber:serial];
    dateCreated = [[NSDate date] init];
    
    return self;
}

-(id)initWithItemName:(NSString *)name setSerialNumber:(NSString *)serial
{
    self = [super init];
    
    [self setItemName:name];
    [self setSerialNumber:serial];
    
    return self;
}

-(void)setItemName:(NSString *)str
{
    itemName = str;
}

-(NSString *)itemName
{
    return itemName;
}

-(void)setSerialNumber:(NSString *)str
{
    serialNumber = str;
}

-(NSString *)serialNumber
{
    return serialNumber;
}

-(void)setValueInDollars:(int)i
{
    valueInDollars = i;
}

-(int)valueInDollars
{
    return valueInDollars;
}

-(NSDate *)dateCreated
{
    return dateCreated;
}

-(NSString *)description
{
    return [NSString stringWithFormat:@"%@ (%@) worth %d, recorded on %@",[self itemName],[self serialNumber],[self valueInDollars], [self dateCreated]];
}

@end

BNRContainer.h

//
//  BNRContainer.h
//  RandomPossessions
//
//  Created by VR2VNA on 2/23/13.
//  Copyright (c) 2013 __MyCompanyName__. All rights reserved.
//

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

@interface BNRContainer : BNRItem
{
    NSString *containerName;
    NSMutableArray *subItems;
    int subLevel;
}
-(void)setSubLevel:(int)level;
-(void)assignSubItems:(NSMutableArray *)sub;
-(NSString *)containerName;
-(void)setContainerName:(NSString *)name;
-(int)totalValue;
@end

BNRContainer.m

//
//  BNRContainer.m
//  RandomPossessions
//
//  Created by VR2VNA on 2/23/13.
//  Copyright (c) 2013 __MyCompanyName__. All rights reserved.
//

#import "BNRContainer.h"

@implementation BNRContainer

-(NSString *)containerName
{
    return containerName;
}

-(void)setContainerName:(NSString *)name
{
    containerName = name;
}

-(int)totalValue
{
    int sum = 0;
    for(id p in subItems) {
        if([p isMemberOfClass:[BNRItem class]])  {
        sum = sum + [p valueInDollars];    
        }
        else if([p isMemberOfClass:[BNRContainer class]])   {
            sum = sum + [p totalValue];
        }
    }
    return sum;
}

-(void)setSubLevel:(int) level
{
    subLevel = level;
}

-(void)assignSubItems:(NSMutableArray *)sub
{
    subItems = sub;
}

-(NSString *)description
{
    NSString *descriptionString = [NSString stringWithFormat:@"%@: Total value in %@ =  %d\n",containerName,containerName,[self totalValue]];

    id obj;

    for(int  i = 0 ; i < [subItems count] ; i ++)   {
        obj = [subItems objectAtIndex:i];
        for(int k=0; k <subLevel ; k++) {
            descriptionString = [descriptionString stringByAppendingFormat:@"--->"];
        }    
        if([obj isMemberOfClass:[BNRContainer class]])    {
            descriptionString = [descriptionString stringByAppendingFormat:@"%@",obj];
        }
        else if([obj isMemberOfClass:[BNRItem class]])  {
            descriptionString = [descriptionString stringByAppendingFormat:@"%@\n",obj];
        }
    }
    return descriptionString;    
}
@end

main.m

//
//  main.m
//  RandomPossessions
//
//  Created by VR2VNA on 2/20/13.
//  Copyright (c) 2013 __MyCompanyName__. All rights reserved.
//

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

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

    @autoreleasepool {
        
        // Create a Mutable Array Object, store addresses in pointers
        NSMutableArray *items = [[NSMutableArray alloc] init];
        NSMutableArray *items2 = [[NSMutableArray alloc] init];
        NSMutableArray *items3 = [[NSMutableArray alloc] init];

        // Create contents for the item arrays
        for(int i = 0; i < 10; i++) {
            BNRItem *p = [BNRItem randomItem];
            [items addObject:p];
        }

        for(int i = 0; i < 10; i++) {
            BNRItem *p = [BNRItem randomItem];
            [items2 addObject:p];
        }

        for(int i = 0; i < 10; i++) {
            BNRItem *p = [BNRItem randomItem];
            [items3 addObject:p];
        }
        
        // Create container3
        BNRContainer *container3 = [[BNRContainer alloc] init];
        [container3 assignSubItems:items3];
        [container3 setSubLevel:2];
        [container3 setContainerName:@"Container3"];
        
        [items2 addObject:container3];
        
        BNRContainer *container2 = [[BNRContainer alloc] init];
        [container2 assignSubItems:items2];
        [container2 setSubLevel:1];
        [container2 setContainerName:@"Container2"];
        
        [items addObject:container2];

        for(int i = 0; i < 5; i++) {
            BNRItem *p = [BNRItem randomItem];
            [items addObject:p];
        }
        BNRContainer *container1 = [[BNRContainer alloc] init];
        
        [container1 assignSubItems:items];
        [container1 setSubLevel:0];
        [container1 setContainerName:@"Container1"];
        
        //Call the description method and Log the output
        NSLog(@"\n%@", container1);        

        items = nil;
    }
    return 0;
}

Description method of BNRContainer.m
When the description method is invoked, each item within the code will be checked. Method isMemberOfClass is used to identify if that item is a BNRContainer or BNRItems. If the items is an BNRContainer Object, the BNRContainer’s description method will be invoked, again. As the description method is being called within a description method, so it is recursive and can down to many level as the OS can handle. [But I found that finally I am passing the same object variable (obj) to the description method, but actually different object is passed to different description method. And I am passing back to this BNRContainer description again. So it is still recursive.]

-(NSString *)description
{
    NSString *descriptionString = [NSString stringWithFormat:@"%@: Total value in %@ =  %d\n",containerName,containerName,[self totalValue]];
    id obj;
    for(int  i = 0 ; i < [subItems count] ; i ++)   {
        obj = [subItems objectAtIndex:i];
        for(int k=0; k <subLevel ; k++) {
            descriptionString = [descriptionString stringByAppendingFormat:@"--->"];
        }    
        if([obj isMemberOfClass:[BNRContainer class]])    {
            descriptionString = [descriptionString stringByAppendingFormat:@"%@",obj];
        }
        else if([obj isMemberOfClass:[BNRItem class]])  {
            descriptionString = [descriptionString stringByAppendingFormat:@"%@\n",obj];
        }
    }
    return descriptionString;    
}

In my test case, I have 3 levels of containers. Container3 within Container2 and within Container1. Every Container also has other BNRItems objects.
Following is the output captured from the console
Console output

2013-02-27 00:20:44.611 RandomPossessions[6059:903] 
Container1: Total value in Container1 =  1788
Rusty Spock (8Q2U8) worth 73, recorded on 2013-02-27 00:20:44 +0800
Shinny Spock (5Y2V3) worth 40, recorded on 2013-02-27 00:20:44 +0800
Rusty Spock (2F9Z7) worth 40, recorded on 2013-02-27 00:20:44 +0800
Rusty Bear (8G5V6) worth 99, recorded on 2013-02-27 00:20:44 +0800
Shinny Spock (3P9B1) worth 10, recorded on 2013-02-27 00:20:44 +0800
Rusty Max (6R5C1) worth 93, recorded on 2013-02-27 00:20:44 +0800
Fluffy Spock (3E4O0) worth 1, recorded on 2013-02-27 00:20:44 +0800
Fluffy Max (3A6T4) worth 30, recorded on 2013-02-27 00:20:44 +0800
Shinny Spock (8S3I1) worth 77, recorded on 2013-02-27 00:20:44 +0800
Rusty Spock (4F6F9) worth 65, recorded on 2013-02-27 00:20:44 +0800
Container2: Total value in Container2 =  1012
--->Fluffy Spock (1P5F4) worth 29, recorded on 2013-02-27 00:20:44 +0800
--->Fluffy Bear (3R2Q6) worth 88, recorded on 2013-02-27 00:20:44 +0800
--->Rusty Bear (4X7P8) worth 38, recorded on 2013-02-27 00:20:44 +0800
--->Shinny Max (7E4L1) worth 77, recorded on 2013-02-27 00:20:44 +0800
--->Shinny Bear (8K9Y2) worth 35, recorded on 2013-02-27 00:20:44 +0800
--->Fluffy Spock (8J8T0) worth 94, recorded on 2013-02-27 00:20:44 +0800
--->Rusty Bear (5E2Z1) worth 42, recorded on 2013-02-27 00:20:44 +0800
--->Fluffy Spock (1K1G7) worth 71, recorded on 2013-02-27 00:20:44 +0800
--->Rusty Max (9X6C8) worth 40, recorded on 2013-02-27 00:20:44 +0800
--->Fluffy Bear (3H0R6) worth 54, recorded on 2013-02-27 00:20:44 +0800
--->Container3: Total value in Container3 =  444
--->--->Fluffy Max (0A4S4) worth 13, recorded on 2013-02-27 00:20:44 +0800
--->--->Rusty Spock (4J8M0) worth 26, recorded on 2013-02-27 00:20:44 +0800
--->--->Shinny Bear (7F7U9) worth 23, recorded on 2013-02-27 00:20:44 +0800
--->--->Shinny Bear (5T0K8) worth 96, recorded on 2013-02-27 00:20:44 +0800
--->--->Rusty Bear (4Y1L2) worth 25, recorded on 2013-02-27 00:20:44 +0800
--->--->Fluffy Spock (6C5F3) worth 18, recorded on 2013-02-27 00:20:44 +0800
--->--->Shinny Spock (7B0S1) worth 53, recorded on 2013-02-27 00:20:44 +0800
--->--->Fluffy Spock (5F8L6) worth 61, recorded on 2013-02-27 00:20:44 +0800
--->--->Fluffy Spock (1C1O0) worth 74, recorded on 2013-02-27 00:20:44 +0800
--->--->Shinny Spock (9F5J9) worth 55, recorded on 2013-02-27 00:20:44 +0800
Shinny Spock (6R2M8) worth 55, recorded on 2013-02-27 00:20:44 +0800
Fluffy Bear (8S7L9) worth 44, recorded on 2013-02-27 00:20:44 +0800
Fluffy Max (4Z5B0) worth 31, recorded on 2013-02-27 00:20:44 +0800
Rusty Spock (0D5P5) worth 54, recorded on 2013-02-27 00:20:44 +0800
Shinny Max (7I4K0) worth 64, recorded on 2013-02-27 00:20:44 +0800