Bronze, Silver, Gold solutions


#1

For what it’s worth, this is what I came up with for the challenges. Seems to work OK.

WCOItemStore.h

#import <Foundation/Foundation.h>

@class WCOItem;

@interface WCOItemStore : NSObject

// A Class method
+ (instancetype)sharedStore;

- (WCOItem *)createItem;

- (void)removeItem:(WCOItem *)item;

- (void)moveItemAtIndex:(NSUInteger)fromIndex
                toIndex:(NSUInteger)toIndex;

- (NSArray *)allItems;

@end

WCOItemStore.m

#import "WCOItemStore.h"
#import "WCOItem.h"

@interface WCOItemStore ()

@property (nonatomic) NSMutableArray *privateItems;

@end

@implementation WCOItemStore

+ (instancetype)sharedStore {
    static WCOItemStore *sharedStore;
    
    // Do I need to create a sharedStore?
    if (!sharedStore) {
        sharedStore = [[self alloc] initPrivate];
    }
    return sharedStore;
}

// If a programmer calls [[WCOItemStore allo] init], let him know the
// error of his ways
- (instancetype)init {
    [NSException raise:@"Singleton"
               format:@"Use +[WCOItemStore sharedStore]"];
    return nil;
}

// Here is the real (secret) initializer
- (instancetype)initPrivate {
    self = [super init];
    if (self) {
        _privateItems = [[NSMutableArray alloc] init];
    }
    return self;
}

- (NSArray *)allItems {
    return [self.privateItems copy];
}

- (WCOItem *)createItem {
    WCOItem *item = [WCOItem randomItem];
    [self.privateItems addObject:item];
    return item;
}

- (void)removeItem:(WCOItem *)item {
    [self.privateItems removeObjectIdenticalTo:item];
}

- (void)moveItemAtIndex:(NSUInteger)fromIndex
                toIndex:(NSUInteger)toIndex {
        
    if (fromIndex == toIndex) {
        return;
    }
    // Get pointer to object being moved so you can re-insert it
    WCOItem *item = self.privateItems[fromIndex];
    
    // Remove item from array
    [self.privateItems removeObjectAtIndex:fromIndex];
    
    // Insert item in array at new location
    [self.privateItems insertObject:item atIndex:toIndex];
}

@end

and WCOItemsViewController.m

#import "WCOItemsViewController.h"
#import "WCOItemStore.h"
#import "WCOItem.h"

@interface WCOItemsViewController ()

@property (nonatomic, strong) IBOutlet UIView *headerView;

@end

@implementation WCOItemsViewController

- (IBAction)addNewItem:(id)sender
{
    // Create a new WCOItem and add it to the store
    WCOItem *newItem = [[WCOItemStore sharedStore] createItem];
    
    // Figure out where that item is in the array
    NSInteger lastRow = [[[WCOItemStore sharedStore] allItems] indexOfObject:newItem];
    
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:lastRow inSection:0];
    // Insert this new row into the table
    [self.tableView insertRowsAtIndexPaths:@[indexPath]
                          withRowAnimation:UITableViewRowAnimationTop];
     
}

- (IBAction)toggleEditingMode:(id)sender {
    // If currently in editing mode
    if (self.isEditing)
    {
        // change text of button to inform user of state
        [sender setTitle:@"Edit" forState:UIControlStateNormal];
        
        // Turn off editing mode
        [self setEditing:NO animated:YES];
        
    } else {
        
        // Change text of button to inform user of state
        [sender setTitle:@"Done" forState:UIControlStateNormal];
        
        // Enter editing mode
        [self setEditing:YES animated:YES];
    }
}

- (instancetype)init {
    
    self = [super initWithStyle:UITableViewStylePlain];
    if (self) {
//        for (int i = 0; i < 5; i++) {
//            [[WCOItemStore sharedStore] createItem];
//        }
    }
    return self;
    
}

- (instancetype)initWithStyle:(UITableViewStyle)style {
    
    return [self init];
    
}

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

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    // Create an instance of UITableViewCell, with a default appearance
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"
                                                            forIndexPath:indexPath];
    
    WCOItem *lastItem = [WCOItem alloc];
    lastItem.itemName = @"No more items.";
    lastItem.serialNumber = @"";
    lastItem.valueInDollars = 0;
    
    // Set the text on the cell with the description of the item that is at the nth index of items,
    // where n = row this cell will appear in on the tableView
    NSArray *items = [[WCOItemStore sharedStore] allItems];
    NSMutableArray *tempItems = [NSMutableArray array];
    
    if (indexPath.section == 0) {
        [tempItems addObjectsFromArray:items];
        [tempItems addObject];
        items = tempItems;
    }
    
    WCOItem *item = items[indexPath.row];
    
    // Set the text on the cell with the description of the item that is at the nth index of items,
    // where n = row this cell will appear in on the tableView
    
    if ([items indexOfObject:item] == [items count] - 1) {
        cell.textLabel.text = [NSString stringWithFormat:@"%@", item.itemName];
    } else {
        cell.textLabel.text = [NSString stringWithFormat:@"$%d - %@", item.valueInDollars, item.description];
        cell.textLabel.font = [UIFont systemFontOfSize:20];
    }
    
  return cell;
}

- (UIView *)headerView {
    // if you have not loaded the header's view yet
    if (!_headerView) {
        // load HeaderView.xib
        [[NSBundle mainBundle] loadNibNamed:@"HeaderView"
                                      owner:self
                                    options:nil];
    }
    return _headerView;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"UITableViewCell"];
    UIView *header = self.headerView;
    [self.tableView setTableHeaderView:header];
}

- (void)tableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath {
    // If the table view is asking to commit a delete
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        
        NSLog(@"Num Rows: %d: ", [self.tableView numberOfRowsInSection:0]);
        
        NSArray *items = [[WCOItemStore sharedStore] allItems];
        
        WCOItem *item = items[indexPath.row];
        
        [[WCOItemStore sharedStore] removeItem:item];
        
        // Also remove that row from the table view with animation
        [tableView deleteRowsAtIndexPaths:@[indexPath]
                         withRowAnimation:UITableViewRowAnimationFade];
        
        NSLog(@"Num Rows: %d: ", [self.tableView numberOfRowsInSection:0]);        
    }
}

- (void)tableView:(UITableView *)tableView
moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath
      toIndexPath:(NSIndexPath *)destinationIndexPath {
    
    [[WCOItemStore sharedStore] moveItemAtIndex:sourceIndexPath.row
                                        toIndex:destinationIndexPath.row];
    
}

- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath {
    return @"Remove";
}

// Make it so that you can't move the No More Items list item
- (BOOL)tableView:(UITableView *)tableView
canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.row == [self.tableView numberOfRowsInSection:0] - 1) {
        return NO;
    } else {
        return YES;
    }
}

// Make it so that No More Items ALWAYS remains at the bottom of the list
- (NSIndexPath *)tableView:(UITableView *)tableView
targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath
       toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath {
    if (proposedDestinationIndexPath.row != [self.tableView numberOfRowsInSection:0] - 1) {
        return proposedDestinationIndexPath;
    } else {
        return sourceIndexPath;
    }
}

// Make it so you can't edit the No More items list item
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
     if (indexPath.row == [self.tableView numberOfRowsInSection:0] - 1) {
         return UITableViewCellEditingStyleNone;
     } else {
         return UITableViewCellEditingStyleDelete;
     }
}

@end