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;
@property (nonatomic, readonly) NSDate *dateCreated;

  • (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.
// Copyright © 2014 Big Nerd Ranch. All rights reserved.
//

#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 adjectiveIndex = arc4random() % [randomAdjectiveList count];
    NSInteger nounIndex = arc4random() % [randomNounList count];

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

    NSString *randomName = [NSString stringWithFormat:@"%@ %@",
    randomAdjectiveList[adjectiveIndex],
    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.
// Copyright © 2014 SwingSI. All rights reserved.
//

#import <Foundation/Foundation.h>

@class BNRItem;

@interface BNRItemStore : NSObject

@property(nonatomic, readonly)NSArray *allItemsOver;

@property(nonatomic, readonly)NSArray *allItemsUnder;

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

@end
[/code]

BNRStore.m

[code]//
// BNRItemStore.m
// Homepwner
//
// Created by Philip Lau on 7/23/14.
// Copyright © 2014 SwingSI. All rights reserved.
//

#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){

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

return item;

}
-(BNRItem *)createLastItem{

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

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

[self.privateItemsUnder50 addObject:item];


return item;

}

@end[/code]

BNRItemsViewController.h

[code]//
// BNRItemsViewController.h
// Homepwner
//
// Created by Philip Lau on 7/23/14.
// Copyright © 2014 SwingSI. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface BNRItemsViewController : UITableViewController

@end
[/code]

BNRItemsViewController.m

[code]//
// BNRItemsViewController.m
// Homepwner
//
// Created by Philip Lau on 7/23/14.
// Copyright © 2014 SwingSI. All rights reserved.
//

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

@implementation BNRItemsViewController

//*ADDED Height of Each Row
-(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];
}

}

//*ADDED #Number of Sections
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 2;
}

//*ADDED Headers for Each Section
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{

if(section == 0){
 
    return @"Section 1: More Than $50";
}
else{
    
    return @"Section 2: Less Than $50";
}

}
//*ADDED Footer for Each Section
-(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];

//*ADDED
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;

}

-(void)viewDidLoad{

[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!