# Another Silver Challenge Solution

#1

It’s really rewarding to first find the solution on your own and then check with other people.

anyhow, here’s the solution for the Silver Challenge

BNRItem.h

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

@interface BNRItem : NSObject

@property (nonatomic, copy) NSString *itemName;
@property (nonatomic, copy) NSString *serialNumber;
@property (nonatomic) int valueInDollars;

• (instancetype)randomItem;

// Designated initializer for BNRItem

• (instancetype)initWithItemName:(NSString *)name
valueInDollars:(int)value
serialNumber:(NSString *)sNumber;

• (instancetype)initWithItemName:(NSString *)name;

-(NSString *)lastDescription;

@end[/code]

BNRItem.m

[code]//
// BNRItem.m
// RandomItems
//
// Created by John Gallagher on 1/12/14.
//

#import “BNRItem.h”

@implementation BNRItem

• (instancetype)randomItem
{
// Create an immutable array of three adjectives
NSArray *randomAdjectiveList = @[@“Fluffy”, @“Rusty”, @“Shiny”];

// Create an immutable array of three nouns
NSArray *randomNounList = @[@“Bear”, @“Spork”, @“Mac”];

// Get the index of a random adjective/noun from the lists
// Note: The % operator, called the modulo operator, gives
// you the remainder. So adjectiveIndex is a random number
// from 0 to 2 inclusive.
NSInteger nounIndex = arc4random() % [randomNounList count];

// Note that NSInteger is not an object, but a type definition
// for “long”

NSString *randomName = [NSString stringWithFormat:@"%@ %@",
randomNounList[nounIndex]];

int randomValue = arc4random() % 100;

NSString *randomSerialNumber = [NSString stringWithFormat:@"%c%c%c%c%c",
‘0’ + arc4random() % 10,
‘A’ + arc4random() % 26,
‘0’ + arc4random() % 10,
‘A’ + arc4random() % 26,
‘0’ + arc4random() % 10];

BNRItem *newItem = [[self alloc] initWithItemName:randomName
valueInDollars:randomValue
serialNumber:randomSerialNumber];

return newItem;
}

• (instancetype)initWithItemName:(NSString *)name
valueInDollars:(int)value
serialNumber:(NSString *)sNumber
{
// Call the superclass’s designated initializer
self = [super init];

// Did the superclass’s designated initializer succeed?
if (self) {
// Give the instance variables initial values
_itemName = name;
_serialNumber = sNumber;
_valueInDollars = value;
// Set _dateCreated to the current date and time
_dateCreated = [[NSDate alloc] init];
}

// Return the address of the newly initialized object
return self;
}

• (instancetype)initWithItemName:(NSString *)name
{
return [self initWithItemName:name
valueInDollars:0
serialNumber:@""];
}

• (instancetype)init
{
return [self initWithItemName:@“Item”];
}

• (void)dealloc
{
NSLog(@“Destroyed: %@”, self);
}

• (NSString *)description
{
NSString *descriptionString =
[[NSString alloc] initWithFormat:@"%@ (%@): Worth \$%d, recorded on %@",
self.itemName,
self.serialNumber,
self.valueInDollars,
self.dateCreated];
return descriptionString;
}

• (NSString *)lastDescription
{
NSString *descriptionString =
[[NSString alloc] initWithFormat:@“No More Items!”];

return descriptionString;
}

@end[/code]

BNRStore.h

[code]//
// BNRItemStore.h
// Homepwner
//
// Created by Philip Lau on 7/23/14.
//

#import <Foundation/Foundation.h>

@class BNRItem;

@interface BNRItemStore : NSObject

+(instancetype)sharedStore;
-(BNRItem *)createItem;
-(BNRItem *)createLastItem;

@end
[/code]

BNRStore.m

[code]//
// BNRItemStore.m
// Homepwner
//
// Created by Philip Lau on 7/23/14.
//

#import “BNRItemStore.h”
#import “BNRItem.h”

@interface BNRItemStore ()

@property (nonatomic)NSMutableArray *privateItemsOver50;

@property (nonatomic)NSMutableArray *privateItemsUnder50;

@end

@implementation BNRItemStore

+(instancetype)sharedStore{

``````static BNRItemStore *sharedStore = nil;

if(!sharedStore){

sharedStore = [[self alloc]initPrivate];

}

return sharedStore;
``````

}

-(instancetype)init{

``````@throw[NSException exceptionWithName:@"Singleton" reason:@"Use+[BNRItemStore sharedStore]" userInfo:nil];

return nil;
``````

}
-(instancetype)initPrivate{

``````self = [super init];

if(self){

_privateItemsOver50 = [[NSMutableArray alloc]init];

_privateItemsUnder50 = [[NSMutableArray alloc]init];

}

return self;
``````

}
-(NSArray*)allItemsOver{

``````    return self.privateItemsOver50;
``````

}
-(NSArray*)allItemsUnder{

``````    return self.privateItemsUnder50;
``````

}

-(BNRItem *)createItem{

``````BNRItem *item = [BNRItem randomItem];

if(item.valueInDollars > 50){

// NSLog(@"Over:%d", item.valueInDollars);
}
else if(item.valueInDollars < 50 && item.valueInDollars > 0){
// NSLog(@"Under:%d", item.valueInDollars);
}

return item;
``````

}
-(BNRItem *)createLastItem{

``````BNRItem *item = [[BNRItem alloc]init];

item.itemName = @"No More Items!";

return item;
``````

}

@end[/code]

BNRItemsViewController.h

[code]//
// BNRItemsViewController.h
// Homepwner
//
// Created by Philip Lau on 7/23/14.
//

#import <Foundation/Foundation.h>

@interface BNRItemsViewController : UITableViewController

@end
[/code]

BNRItemsViewController.m

[code]//
// BNRItemsViewController.m
// Homepwner
//
// Created by Philip Lau on 7/23/14.
//

#import “BNRItemsViewController.h”
#import “BNRItemStore.h”
#import “BNRItem.h”

@implementation BNRItemsViewController

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{

``````    return 160;
``````

}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

``````if(section == 0){

return [[[BNRItemStore sharedStore]allItemsOver]count];
}
else{

return [[[BNRItemStore sharedStore]allItemsUnder]count];
}
``````

}

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 2;
}

``````if(section == 0){

return @"Section 1: More Than \$50";
}
else{

return @"Section 2: Less Than \$50";
}
``````

}
-(NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{

``````if (section == 1) {
return @"This is the footer.";
}
else{

return @"";

}
``````

}

-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

``````UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell" forIndexPath:indexPath];

if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"UITableViewCell"];
}

if(indexPath.section == 0){

NSArray *items = [[BNRItemStore sharedStore]allItemsOver];

BNRItem *item = items[indexPath.row];

cell.textLabel.text = [item description];

}
else if(indexPath.section == 1){

NSArray *items = [[BNRItemStore sharedStore]allItemsUnder];

BNRItem *item = items[indexPath.row];

if(items[indexPath.row] == [items lastObject]){

cell.textLabel.text = [item lastDescription];

}
else{
cell.textLabel.text = [item description];
}

}

return cell;
``````

}

``````[super viewDidLoad];

[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"UITableViewCell"];
``````

}

-(instancetype)init{

``````self = [super initWithStyle:UITableViewStylePlain];

if(self){

for(int i=0; i < 25; i++){

[[BNRItemStore sharedStore] createItem ];

}

[[BNRItemStore sharedStore] createLastItem];
}

return self;
``````

}

-(instancetype)initWithStyle:(UITableViewStyle)style{

``````return [self init];
``````

}

@end
[/code]

Enjoy!

#2

I had the same idea, but when creating lastItem you are still initializing it with the default values. I didn’t create a new description string though. Does this work and display only “No more items!” at the end of the list instead of “No more items!” followed by all the default values?

Edit: I get it now, lastDescription doesn’t call each of the values so it only displays the name. This was what I was missing in mine. Thanks for the post!

#3

That’s a nice solution. I’m not yet an expert on MVC design principles, but I believe you solutions violates the principle of keeping the model separate from the view. For example, you’re adding properties to BNRItemStore.h, which is a model object, with the intent of modifying the view. This challenge is only asking for the view to change, so I believe that the model should not be touched.

I used a Footer instead, you can see the solution here: github.com/idrisr/objCBNR/tree/silver

#4

What do you think about the solution below?

1. Add one more ROW in tableView numberOfRowsInSection
2. Deal with the last ROW
if ([indexPath indexAtPosition:1] == [items count]) {
}

## Thanks

• (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[[BNRItemStore sharedStore] allItems] count] + 1;
}

-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"
forIndexPath:indexPath];

``````NSArray *items = [[BNRItemStore sharedStore] allItems];
``````

if ([indexPath row] == [items count])
{
cell.textLabel.text = @“No more items”;
return cell;
}

``````BNRItem  *item = [items objectAtIndex:indexPath.row];

cell.textLabel.text = item.description;

return cell;
``````

}

#5

[quote]What do you think about the solution below?

1. Add one more ROW in tableView numberOfRowsInSection
2. Deal with the last ROW[/quote]

I was trying to do what you did, but couldn’t work it out. My thought process was correct though - just modify the view.

You get extra points for simplicity!