Chapter 8 Solution - Bronze, Silver, Gold Challenges w/outpu

#1

[size=120]OUTPUT[/size]:

These were great challenges, really puts tableview <–> datasource/delegate concepts to practice. I had a hard time at first with the sections but It was fun to figure it out on my own, and the rest just flowed from there.

ZGCItemsTableViewController

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

@interface ZGCItemsTableViewController : UITableViewController

@end[/code]

ZGCItemsTableViewController.m

[code]#import “ZGCItemsTableViewController.h”
#import “ZGCItemStore.h”
#import “ZGCItem.h”

@interface ZGCItemsTableViewController ()

@end

@implementation ZGCItemsTableViewController

/* Changing designated initializer to “init” (default is initWithStyle:)
then will override superclass’ designated initializer to call this one */

  • (instancetype)init {
    // Call superclass designated initializer (rule)
    self = [super initWithStyle:UITableViewStylePlain];
    if (self) {
    for (int i = 0; i < 5; i++) {
    [[ZGCItemStore sharedStore] createItem]; // initiates store, create 5 items
    }
    }
    return self;
    }

/* Overriding superclass designated initializer to call mine */

  • (instancetype)initWithStyle:(UITableViewStyle)style {
    return [self init]; // all instances will now use plainviewstyle
    }

  • (void)viewDidLoad {
    [super viewDidLoad];

    /* This is required to tell the tableview which kind of cell
    it should instantiate if there are no cells in the reuse pool
    when cellForView protocol method is called */
    [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@“UITableViewCell”];

    /* same as above but for the footer/header object */
    [self.tableView registerClass:[UITableViewHeaderFooterView class] forHeaderFooterViewReuseIdentifier:@“UITableViewHeaderFooterView”];

    /* GOLD CHALLENGE part make rows size 60 */
    self.tableView.rowHeight = 60;

    /* SILVER CHALLENGE part required by the delegate methods below that return footers/headers */
    self.tableView.sectionFooterHeight = 44;
    self.tableView.sectionHeaderHeight = 60;

    /* ** GOLD CHALLENGE part** add background image to TableView */
    UIImageView *background = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@“1410296829223.jpg”]];
    self.tableView.backgroundView = background;

    // Uncomment the following line to preserve selection between presentations.
    // self.clearsSelectionOnViewWillAppear = NO;

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem;
    }

  • (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
    }

#pragma mark - Table view data source

  • (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    #warning Potentially incomplete method implementation.
    // Return the number of sections.

    return 2;
    }

  • (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    // #warning Incomplete method implementation.
    // Return the number of rows in the section. equals n. of items in array

    // return [[[ZGCItemStore sharedStore] allItems] count];

    NSArray *items = [[ZGCItemStore sharedStore] allItems];
    int sum = 0;
    if (section == 0) {
    for (ZGCItem *i in items) {
    if (i.valueInDollars > 50.0) {
    sum++;
    }
    }
    }

    if (section == 1) {
    for (ZGCItem *i in items) {
    if (i.valueInDollars < 50.0) {
    sum++;
    }
    }
    }

    return sum;
    }

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

    /*
    // Create an instance of UITableViewCell, with default apperance
    UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@“UITableViewCell”];
    */

    // Using conventional method to create UITableViewCell object via resuable indent.
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@“UITableViewCell” forIndexPath:indexPath];

    /* **GOLD CHALLENGE part ** make text for rows text size 20 */
    cell.textLabel.font = [UIFont systemFontOfSize:20];

    // Set the text on the cell with the descripton of the item
    // that is at the nth index of items (n = row this cell will appear on)
    NSArray *items = [[ZGCItemStore sharedStore] allItems];

    /* BRONZE CHALLENGE // – using 2 sections, one for items > $50 bucks / one for < */
    // Define two arrays to store rows (items) for each section
    NSMutableArray *section0 = [[NSMutableArray alloc] init];
    NSMutableArray *section1 = [[NSMutableArray alloc] init];

    // if value satisfy requireent, add to appropiate array
    for (ZGCItem *i in items) {
    if (i.valueInDollars > 50.0) {
    [section0 addObject:i];
    } else {
    [section1 addObject:i];
    }
    }

    // pull item from requested section out of respective array and configure cell object
    if (indexPath.section == 0) {
    ZGCItem *item = section0[indexPath.row];
    cell.textLabel.text = [item description];

    } else if (indexPath.section == 1) {
    ZGCItem *item = section1[indexPath.row];
    cell.textLabel.text = [item description];
    }

    return cell;

}

#pragma mark - tableview delegate methods

/// SILVER CHALLENGE /// - footer that says ‘no more items!’(added header as well)

  • (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {

    UITableViewHeaderFooterView *footer = [tableView dequeueReusableHeaderFooterViewWithIdentifier:@“UITableViewHeaderFooterView”];
    footer.textLabel.text = @“No more items!”;

    return footer;
    }

  • (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {

    UITableViewHeaderFooterView *header = [tableView dequeueReusableHeaderFooterViewWithIdentifier:@“UITableViewHeaderFooterView”];

    header.contentView.backgroundColor = [UIColor lightGrayColor];

    if (section == 0) {
    header.textLabel.text = @“Items > $50”;
    }
    if (section == 1) {
    header.textLabel.text = @“Items < $50”;
    }

    return header;
    }[/code]

ZGCItem.h

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

@interface ZGCItem : NSObject

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

// Class method

  • (instancetype)randomItem;

// Designated initializer for BNRItem

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

// Additional initializer

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

@end[/code]

ZGCItem.m

[code]#import “ZGCItem.h”

@interface ZGCItem ()

@property (nonatomic, strong) NSDate *dateCreated;

@end

@implementation ZGCItem

  • (instancetype)randomItem
    {
    // Create an array of three adjectives
    NSArray *randomAdjectiveList = @[@“Fluffy”, @“Rusty”, @“Shiny”];
    // Create an 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 = rand() % [randomAdjectiveList count];
    NSInteger nounIndex = rand() % [randomNounList count];
    // Note that NSInteger is not an object, but a type definition
    // for “unsigned long”
    NSString *randomName = [NSString stringWithFormat:@"%@ %@",
    randomAdjectiveList[adjectiveIndex],
    randomNounList[nounIndex]];
    // a random integer for value
    int randomValue = rand() % 100;

    NSString *randomSerialNumber = [NSString stringWithFormat:@"%c%c%c%c%c",
    ‘0’ + rand() % 10,
    ‘A’ + rand() % 26,
    ‘0’ + rand() % 10,
    ‘A’ + rand() % 26,
    ‘0’ + rand() % 10];
    // create new item with the random values
    ZGCItem *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
    self.itemName = name;
    self.serialNumber = sNumber;
    self.valueInDollars = value;
    self.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”
    valueInDollars:0
    serialNumber:@""];
    }

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

    return descriptionString;
    }

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

@end

[/code]

ZGCItemStore.h

[code]#import <Foundation/Foundation.h>
@class ZGCItem; // no need to know all the details for this [declarations] file, just that it exists. allows you to use ‘ZGCItem’ in declarations basically.

@interface ZGCItemStore : NSObject

@property (nonatomic, readonly) NSArray *allItems; // return only array for populating tableview

/* To get a single instance of this class we send it the sharedStore message
via this Class method we are declaring */

  • (instancetype)sharedStore;
  • (ZGCItem *)createItem;

@end[/code]

ZGCItemStore.m

[code]#import “ZGCItemStore.h”
#import “ZGCItem.h” //import is required here (not @class)

@interface ZGCItemStore ()
@property (nonatomic) NSMutableArray *privateItems; // mutability hidden via extension

@end

@implementation ZGCItemStore

  • (instancetype)sharedStore {
    // Declaring this variable as static - static variable is not destroyed when method is done executing, It is not kept on the stack (just as a global variables)
    static ZGCItemStore *sharedStore = nil;

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

/* If a programmer calls [[ZGCItemStore alloc] init], let him know
the error of his ways */

  • (instancetype)init {
    @throw [NSException exceptionWithName:@“Singleton” reason:@“User +[ZGCItemStore sharedStore]” userInfo:nil];
    return nil;
    }

/* Here is the real (secret) initiliazer */

  • (instancetype)initPrivate {
    self = [super init];
    if (self) {
    _privateItems = [[NSMutableArray alloc] init];
    }
    return self;
    }

/* Overriding getter for allItems to return privateItems (mutable version) as NSarray */

  • (NSArray *)allItems {
    return self.privateItems; // returninig NSArray type (true way: [self.privateItems copy]
    }

  • (ZGCItem *)createItem {
    ZGCItem *item = [ZGCItem randomItem];
    [self.privateItems addObject:item];

    return item;
    }

@end[/code]

github.com/fsck66/iOS_Book_Proj … _Challenge