Bronze solution


#1

This is my solution for the Bronze challenge, any feedback welcome:

[code]//
// ItemsViewController.m
// Homepwner
//
// Created by Admin on 7/29/13.
// Copyright © 2013 Admin. All rights reserved.
//

#import “ItemsViewController.h”

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

@implementation ItemsViewController

// init method of ItemsViewController
-(id) init
{
self = [super initWithStyle:UITableViewStyleGrouped];

if(self)
{
    itemsLessThanFifty = [[NSMutableArray alloc] init];
    itemsMoreThanFifty = [[NSMutableArray alloc] init];
    
    for(int i = 0; i<5; i++){
         // Add five random elements to the BNRItemStore
         // Remember BNRItemStore is a singleton
        [[BNRItemStore sharedStore] createItem];
        
        BNRItem *temp = [[[BNRItemStore sharedStore] allItems]
                     objectAtIndex:i];
        int value = temp.valueInDollars;
        
        if(value<50)
           [itemsLessThanFifty addObject:temp];
        else
           [itemsMoreThanFifty addObject:temp];

        
    }
    
}

return self;

}

// init method
-(id) initWithStyle:(UITableViewStyle)style
{
return [self init];
}

#pragma mark TableView methods

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

  • (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
    int moreThanFifty = 0;
    int lessThanFifty = 0;

    for(BNRItem * item in [[BNRItemStore sharedStore] allItems])
    {
    if(item.valueInDollars>50)
    moreThanFifty++;
    else
    lessThanFifty++;
    }

    if(section == 0)
    return moreThanFifty;
    else
    return lessThanFifty;
    }

// Tell the UITableView how to draw its each cell

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

    // Check for a reusable cell first, use that if it exists
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@“UITableViewCell”];

    // If there is no reusable cell of this type, create a new one
    if (!cell) {
    cell = [[UITableViewCell alloc]
    initWithStyle:UITableViewCellStyleDefault
    reuseIdentifier:@“UITableViewCell”];
    }

    if(indexPath.section == 0)
    {
    BNRItem *temp = [itemsMoreThanFifty objectAtIndex:indexPath.row];
    [[cell textLabel] setText:[temp description]];
    }else
    {
    BNRItem *temp = [itemsLessThanFifty objectAtIndex:indexPath.row];
    [[cell textLabel] setText:[temp description]];
    }

    return cell;

}

@end
[/code]


#2

Hey user2568508,
I would greatly appreciate if you explain one string in your code.
It’s regarding the “section” property that is being tested in the “if” statement in the "tableView: cellForRowAtIndexPath: " method.
That method, should return a table cell in appropriate section of our table.
At the last stage of this method, we should specify to which section our newly made cell will go.
At first I tried this code:

[code] int sec1=[indexPath section];

if ( sec1 == 1) {
    BNRItem *p = [[[BNRItemStore defaultStore] lessThan50] objectAtIndex:[indexPath row]];
    [[cell textLabel] setText:[p description]];
}
else if (sec1 ==2)
{    BNRItem *o = [[[BNRItemStore defaultStore] moreThan50] objectAtIndex:[indexPath row]];
[[cell textLabel] setText:[o description]];
}
return cell;[/code]

But it didn’t work. I assumed that 1 and 2 are sort of an index numbers by which we can refer to each section. Apparently our declaration that there will be 2 sections doesn’t assign 1 and 2 to each section.
After adjusting my solution to your logic of testing sections, I changed it to the following:

[code]int sec1=[indexPath section];

if ( sec1 == 0) {
    BNRItem *p = [[[BNRItemStore defaultStore] lessThan50] objectAtIndex:[indexPath row]];
    [[cell textLabel] setText:[p description]];
}
else
{    BNRItem *o = [[[BNRItemStore defaultStore] moreThan50] objectAtIndex:[indexPath row]];
[[cell textLabel] setText:[o description]];
}
return cell;[/code]

And it worked.
Can anyone explain, why we have to test “sec1==0”? Is it because sections really do have an index number and in case of two sections, index numbers are “0” and “1”?
(I think that must be it. How awesome is that I realized it only after writing this post. Hopefully it is true)


#3

[quote=“ZhenyaVlasov”]Can anyone explain, why we have to test “sec1==0”? Is it because sections really do have an index number and in case of two sections, index numbers are “0” and “1”?
(I think that must be it. How awesome is that I realized it only after writing this post. Hopefully it is true)[/quote]

You can just put

in the tableView:numberOfRowsInSection: method to see the index number of each section. For me, they are 1 and 0.


#4

Cool. I guess any set of object - sections, views, table cells -are all, in essence, parts of arrays.


#5

In many programming languages indexes into arrays and other indexed data structures tend to be zero-based - the first item is at index 0 and the last item is at (count - 1).

The reason stems back to how static arrays work under the covers; the index is actually an offset into a block of memory - multiply the index by the size of each item and you have the offset in bytes where that item will start. Since the first item starts at the beginning of the block of memory its offset is naturally zero.

Once you are using zero-based indexes for arrays it makes sense to stick to that for any thing else that holds a list for consistency.


#6

At first I thought of a few approaches:

  • use an NSDictionary to hold the separate items
  • sort the allItems array by value and split them later
  • implement two methods in BNRItemStore to hold the separated items

But I think probably one of the simplest way to address the challenge is to use a solution similar to the original post. Since the view controller is also a data source, why not create a couple of instance variables to handle the way the data is displayed without the need to modifying the original list in allItems.

The final approach I used is very similar to the original post, with the exception of the count method used to return the number of rows in a section.

//
//  ItemsViewController.m
//  Homepwner
//
//  Created by on 10/11/13.
//  Copyright (c) 2013 __MyCompanyName__. All rights reserved.
//

#import "ItemsViewController.h"
#import "BNRItemStore.h"
#import "BNRItem.h"

@implementation ItemsViewController


- (id)initWithStyle:(UITableViewStyle)style

{
    return [self init];
}

- (id)init
{
    // Call the superclass's designated initializer
    self = [super initWithStyle:UITableViewStyleGrouped];
    if (self) {
        
        // *** Bronze Challenge: Sections
        // Added two NSMutableArray instance variable (declared in 
        // ItemsViewController.h) to store the over/under items
        itemsOverFifty = [[NSMutableArray alloc] init];
        itemsUnderFifty = [[NSMutableArray alloc] init];
        
        // Populate the BNRItemStore with random items
        for (int i = 0; i < 5; i++) {
            [[BNRItemStore sharedStore] createItem];
            
            // Get a pointer to the item just created...
            BNRItem *p = [[[BNRItemStore sharedStore] allItems]
                          objectAtIndex:i];
            
            // ...and check the value in order to separate them into the over or
            // under arrays.
            if ([p valueInDollars] > 50) {
                [itemsOverFifty addObject:p];
            } else {
                [itemsUnderFifty addObject:p];
            }
        }
    }
    return self;
}

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

- (NSInteger)tableView:(UITableView *)tableView 
 numberOfRowsInSection:(NSInteger)section
{
    // Uncomment to determine sections
    // NSLog(@"Section = %d", section);
    
    // Use the count method inherited by NSArray to return number of rows in a section 
    if (section == 0) {
        return [itemsOverFifty count];
    } else {
        return [itemsUnderFifty count];
    }
    
}

- (UITableViewCell *)tableView:(UITableView *)tableView 
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    
    // Check for a reusable cell first, use that if exists
    UITableViewCell *cell = 
        [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"];
    
    // If there is no reusable cell of this type, create a new one
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 
                                      reuseIdentifier:@"UITableViewCell"];
    }
    
    // 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
    
    // Which section are we currently dealing with?
    int section = [indexPath section];
    
    if (section == 0) {
        BNRItem *p = [itemsOverFifty objectAtIndex:[indexPath row]];
        [[cell textLabel] setText:[p description]];
    } else {
        BNRItem *p = [itemsUnderFifty objectAtIndex:[indexPath row]];
        [[cell textLabel] setText:[p description]];
    }
    
    return cell;
}

@end