Bronze challenge (works) but compiler question

#1

After many hours, I finally got it to work. What threw me, though, was the need to duplicate code in the

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method. Why is it necessary to duplicate all the code in the if/else statement? If I didn’t do that, I got a compiler error of “unknown variable” for BNRItem *item. I have programmed in other languages before, and I can understand why at runtime there might be a problem, but why at compile time? In other words, if I allocated and initialize the various arrays in the (if) branch, like this:

BNRItemStore *store = [BNRItemStore sharedStore];
NSMutableArray *array = [store itemValueLt50];
BNRItem *item = array[row];
cell.textLabel.text = [item description];

…why is it necessary to do all the same thing in the (else) branch? Am I missing a compiler option that needs to be set?

[code]//
// BNRItemsViewController.m
// Homepwner
//
// Created by Nelson Capes on 8/25/15.
// Copyright © 2015 Nelson Capes. All rights reserved.
//

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

@implementation BNRItemsViewController

-(instancetype)init
{
// call the superclass’s designated initializer
self = [super initWithStyle:UITableViewStyleGrouped];
if (self){
for (int i = 0; i < 5; i++){
[[BNRItemStore sharedStore]createItem];
}
}
return self;
}

-(instancetype)initWithStyle:(UITableViewStyle)Style
{
return [super init];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// the tableView sends the above message to the view controller (self)
// so that the view controller will return the number of sections
// in the tableView. Here, we hard code the number of sections to 2
return 2;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// the tableView sends the above message to the view controller (self)
// so that the view controller will return the number of rows in each section
//of the tableView
// calculate the number of rows needed in the tableview for each section
// BNRItems with a valuInDollars < 50 go in the first section, itemValueLt50
// BNRItems with a valueInDollars of greater than or equal to 50 go in
// the second section, itemValueGe50

NSInteger s = section;
if (s == 0){
    BNRItemStore *store = [BNRItemStore sharedStore];
    NSMutableArray *array = [store itemValueLt50];
    NSInteger count = [array count];
    return count;
}
else{
    BNRItemStore *store = [BNRItemStore sharedStore];
    NSMutableArray *array = [store itemValueGe50];
    NSInteger count = [array count];
    return count;
}

}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// get a new or recycled cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@“UITableViewCell” forIndexPath:indexPath];
// the tableView sends the view controller (self( the above message with an indexPath
// of section and row so that the view controller will return an initialized cell
// for that section and row to the tableView
//
// 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 the section number is 0, we return a cell from the array itemValueLt50 at
// the row passed in the NSPath parameter, otherwise we return a cell
// from the array itemValueGe50

NSIndexPath *path = indexPath;
NSInteger section = path.section;
NSInteger row = path.row;

if (section == 0){
    BNRItemStore *store = [BNRItemStore sharedStore];
    NSMutableArray *array = [store itemValueLt50];
    BNRItem *item = array[row];
    cell.textLabel.text = [item description];
}
else{
    BNRItemStore *store = [BNRItemStore sharedStore];
    NSMutableArray *array = [store itemValueGe50];
    BNRItem *item = array[row];
    cell.textLabel.text = [item description];
}


return cell;

}

-(void)viewDidLoad
{
[super viewDidLoad];

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

}

@end
[/code]

#2

Hello Nelson,

No, there is no compiler option that you can set.

It sounds like you have started coding in Objective-C without learning the C Programming Language first.

What you are struggling with is the concept of scopes. Roughly speaking, a scope is a container. It provides an environment in which names are defined locally. A scope can contain other scopes. A nested scope inherits all the names defined in the containing scopes, but it can override any name it inherits. A pair of curly braces { and } signal the start and end of a scope, respectively. When a scope ends, everything in it is destroyed automatically (again roughly speaking.)

If you are concerned about repeated name declarations in independent scopes, you can always move the names up into the nearest containing scope whenever it is possible to do so.

NSMutableArray * array = nil;
BNRItemStore * store = [BNRItemStore sharedStore];
if (section == 0)
{
    array = [store itemValueLt50];
}
else {
    array = [store itemValueGe50];
}
BNRItem * item = array[row];
cell.textLabel.text = [item description];

I hope this helps.

#3

[quote=“ibex10”]Hello Nelson,

No, there is no compiler option that you can set.

It sounds like you have started coding in Objective-C without learning the C Programming Language first.

What you are struggling with is the concept of scopes. Roughly speaking, a scope is a container. It provides an environment in which names are defined locally. A scope can contain other scopes. A nested scope inherits all the names defined in the containing scopes, but it can override any name it inherits. A pair of curly braces { and } signal the start and end of a scope, respectively. When a scope ends, everything in it is destroyed automatically (again roughly speaking.)

If you are concerned about repeated name declarations in independent scopes, you can always move the names up into the nearest containing scope whenever it is possible to do so.

NSMutableArray * array = nil;
BNRItemStore * store = [BNRItemStore sharedStore];
if (section == 0)
{
    array = [store itemValueLt50];
}
else {
    array = [store itemValueGe50];
}
BNRItem * item = array[row];
cell.textLabel.text = [item description];

I hope this helps.[/quote]

Thanks much! I found this in my Objective-C book.

In a function definition, any pair of curly braces { … }) define the scope of the code that is in between them. A variable cannot be accessed outside of the scope that it is declared in. In fact, it does not exist outside of the scope that it is declared in. Any pair of braces, whether they are a part of a function definition, an if statement, or a loop, defines its own scope that restricts the availability of any variables declared within them.

Hillegass, Aaron; Ward, Mikey (2013-11-20). Objective-C Programming: The Big Nerd Ranch Guide (2nd Edition) (Big Nerd Ranch Guides) (Kindle Locations 976-981). Pearson Education. Kindle Edition. <<