Bronze Challenge - My Solution + question


#1

My granpappy always said that there was more than one way to skin a cat, some a lot more messy than others. Well the following solution is messy :slight_smile:

I realized that BNRItem was assigned a valueInDollars and so I decided to create 2 arrays instead of the allItems array and put the BNRItem in the appropriate array:

From BNRItemStore.h:

@interface BNRItemsStore : NSObject {
    NSMutableArray *expensiveItems;
    NSMutableArray *cheapItems;
}

-(NSArray *)expensiveItems;
-(NSArray *)cheapItems;

-(BNRItem *)createitem;

+(BNRItemsStore *)sharedStore;

From there I changed the BNRItemStore.m file wherever there was all items, I changed to my 2 newly created arrays:

-(id)init {
    self = [super init];
    if (self) {
        expensiveItems = [[NSMutableArray alloc] init];
        cheapItems = [[NSMutableArray alloc] init];        
}
    return self;
}

-(NSArray *)expensiveItems {
    return expensiveItems;
}

-(NSArray *)cheapItems {
    return cheapItems;
}

// determine the value and add to the right array.
-(BNRItem *)createitem {
    BNRItem *p = [BNRItem randomItem];
    if ([p valueInDollars] > 50) {
        [expensiveItems addObject:p];
    }
    if ([p valueInDollars] <= 50) {
        [cheapItems addObject:p];
    }
    return p;                  
}

Now for the tricky part that had me stumped for a while:

1st part was to create 2 sections. Initially i just returned 2 but realized that wasn’t very scalable. I then experimented with incrementing a variable if the count of the array was greater than 1.

ItemsViewController.m:

// step 1: create 2 sections
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    //return 2;    
    NSInteger i = 0;
    if([[[BNRItemsStore sharedStore] expensiveItems] count] > 0) i++;
    if([[[BNRItemsStore sharedStore] cheapItems] count] > 0) i++;
    return i;
}

Next I needed to determine how many rows go in each section:

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (section == 0) {
        return [[[BNRItemsStore sharedStore] expensiveItems] count];
    } else {
        return [[[BNRItemsStore sharedStore] cheapItems] count];
    }
}

I essentially assigned expensive items to the first section and everything else to cheap items. NOT very elegant (even I can see that) but I didn’t know how else to do it.
The final piece of the puzzle was to figure out how to write to the rows in each section with appropriate data:

//bronze challenge. determine the section and put the right item in the correct section.
    if ([indexPath section] == 0) {
        BNRItem *p = [[[BNRItemsStore sharedStore] expensiveItems] objectAtIndex:[indexPath row]];
        [[cell textLabel] setText:[p description]];
    } else {
        BNRItem *p = [[[BNRItemsStore sharedStore] cheapItems] objectAtIndex:[indexPath row]];
        [[cell textLabel] setText:[p description]];
    }
    return cell;

Again, not very elegant. This solution doesn’t seem to scale very well. For example what happens if there is a ‘super expensive’ category. I would have to go in and refactor all the code. Any pointers or suggestions welcome. thx

On a side note: My BNRItem’s aren’t that random. I keep getting the same values. Anyone else have that? Is rand() not that random?


#2

Hi syndrome
My solution is similar to yours, except I have took another way to get the elements < or > than 50.

In my BNRItemStore I have implemented this:

[code]- (NSArray *)itemsLess:(int)value
{
NSMutableArray *items = [[NSMutableArray alloc] init];

for (BNRItem *item in allItems) {
    if([item valueInDollars] < value) {
        [items addObject:item];
    }
}

return items;

}

  • (NSArray *)itemsMore:(int)value
    {
    NSMutableArray *items = [[NSMutableArray alloc] init];

    for (BNRItem *item in allItems) {
    if([item valueInDollars] > value) {
    [items addObject:item];
    }
    }

    return items;
    }[/code]

So, I can get the elements < or > than the value I want, and I didnt set any class’s attribute.

The methods for the number of rows and the cell are equal, except I ask [BNRItemStore sharedStore]itemsLess… or itemsMore… instead of the array that you created.

I hope I posted it easily. If not let me know if you have doubt.


#3

Syndrome -

I was wondering the same thing about the ‘randomness’. I’m still reading, trying to wrap my head around it, but what I did is replace rand() with arc4random() (in BNRItem.m) and it generates different random items each time. It has something to do with seed numbers and pattern generation I believe. I’d like to be able to give you an answer, but I guess a workaround is all I can offer at this point. Maybe someone else can pipe in and shed some light on this.

Mark


#4

I used an alternate way for this challenge using NSPredicate. Found this from the BNR iOS Programming 2nd Edition forums developer.apple.com/library/ios/ … cates.html. NSArray has a filteredArrayUsingPredicate: method. Using this method along with the predicates allows you to parse the allItems array without having to create two separate arrays. Not sure how this stacks up performance-wise, but it keeps the code simple without having to make changes to the data store class.
ItemViewController.m - tableView:cellForRowAtIndexPath:

[code]- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@“UITableViewCell”];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:@“UITableViewCell”];
}
// Bronze Challenge - Create predicate to filter the array using valueInDollars search string
NSPredicate *predicate;
if ([indexPath section] == 0) {
predicate = [NSPredicate predicateWithFormat:@“valueInDollars > 50”];
} else {
predicate = [NSPredicate predicateWithFormat:@“valueInDollars <= 50”];
}

// Create a filtered array based on the predicate
NSArray *filteredArray = [[[BNRItemStore sharedStore] allItems] filteredArrayUsingPredicate:predicate];
// Create item to be used for the cell using the filtered array
BNRItem *item = [filteredArray objectAtIndex:[indexPath row]];
// Set the cell’s text using the item
[[cell textLabel] setText:[item description]];
return cell;
}[/code]ItemViewController.m - tableView:NumberOfRowsInSection:

[code]- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
NSPredicate *predicate;
if (section == 0) {
predicate = [NSPredicate predicateWithFormat:@“valueInDollars > 50”];
} else {
predicate = [NSPredicate predicateWithFormat:@“valueInDollars <= 50”];
}

NSArray *filteredArray = [[[BNRItemStore sharedStore] allItems] filteredArrayUsingPredicate:predicate];
NSInteger numRows = [filteredArray count];
return numRows;

}[/code]


#5

[quote=“BryanLuby”]I used an alternate way for this challenge using NSPredicate. Found this from the BNR iOS Programming 2nd Edition forums developer.apple.com/library/ios/ … cates.html. NSArray has a filteredArrayUsingPredicate: method. Using this method along with the predicates allows you to parse the allItems array without having to create two separate arrays. Not sure how this stacks up performance-wise, but it keeps the code simple without having to make changes to the data store class.
ItemViewController.m - tableView:cellForRowAtIndexPath:

[code]- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@“UITableViewCell”];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:@“UITableViewCell”];
}
// Bronze Challenge - Create predicate to filter the array using valueInDollars search string
NSPredicate *predicate;
if ([indexPath section] == 0) {
predicate = [NSPredicate predicateWithFormat:@“valueInDollars > 50”];
} else {
predicate = [NSPredicate predicateWithFormat:@“valueInDollars <= 50”];
}

// Create a filtered array based on the predicate
NSArray *filteredArray = [[[BNRItemStore sharedStore] allItems] filteredArrayUsingPredicate:predicate];
// Create item to be used for the cell using the filtered array
BNRItem *item = [filteredArray objectAtIndex:[indexPath row]];
// Set the cell’s text using the item
[[cell textLabel] setText:[item description]];
return cell;
}[/code]ItemViewController.m - tableView:NumberOfRowsInSection:

[code]- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
NSPredicate *predicate;
if (section == 0) {
predicate = [NSPredicate predicateWithFormat:@“valueInDollars > 50”];
} else {
predicate = [NSPredicate predicateWithFormat:@“valueInDollars <= 50”];
}

NSArray *filteredArray = [[[BNRItemStore sharedStore] allItems] filteredArrayUsingPredicate:predicate];
NSInteger numRows = [filteredArray count];
return numRows;

}[/code][/quote]

I loved this solution. And I learned about predicates. +1!


#6

[quote=“syndrome”]I decided to create 2 arrays instead of the allItems array and put the BNRItem in the appropriate array
[/quote]

My first implementation of this challenge was nearly identical; in BNRItemStore replaced allItems with two arrays cheapItems and expensiveItems etc., modified createItem in the same way, and sprinkled the rest of the necessary logic into ItemViewController. Then I had second thoughts. I suspect that BNRItemStore is part of the Model, and thus making changes to it in order to accomodate a desired change to the View would infringe upon the MVC design pattern; my revised solution does the work of seperating allItems into two arrays in ItemViewController and leaves BNRItemStore unchanged from the original. Any thoughts about this question of where the BNRItemStore (and, generally, the parts of the UITableViewController playing the role of data source to the UITableView) fit into MVC?

Dan


#7

@Dan Here is my ugly solution of what you just mentioned, the rest is pretty much the same, this code includes parts of the Silver and Gold Challenge

[code]- (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// First check if there is a cell that has gone off screen that can be reused

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"];

if (!cell) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"UITableViewCell"];
}

// Fetch item

// Creating two arrays to divide up the objects into two sections

NSMutableArray *section50 = [[NSMutableArray alloc] init];
NSMutableArray *sectionRest = [[NSMutableArray alloc] init];

for (BNRItem* item in [[BNRItemStore sharedStore] allItems]) {
    if ([item valueInDollars] > 50) {
        [section50 addObject:item];
    }
    else
        [sectionRest addObject:item];
}

// If this cell is section 0 then add an object corresponding to that section (value less than 50)

// If this is the last cell then add "No more items!" to the end

if ([indexPath section] == 0) {
    if ([indexPath row] == [section50 count]) {
        [[cell textLabel] setText:@"No more Items!"];
    }
    else {
    [[cell textLabel] setText:[[section50 objectAtIndex:[indexPath row]] description]];
    [[cell textLabel] setFont:[UIFont systemFontOfSize:20]];
        [cell sizeThatFits:CGSizeMake(cell.bounds.size.width, 100)];
    }
}
else
    if ([indexPath row] == [sectionRest count]) {
        [[cell textLabel] setText:@"No more Items!"];
        
    }
    else {
    [[cell textLabel] setText:[[sectionRest objectAtIndex:[indexPath row]] description]];
    [[cell textLabel] setFont:[UIFont systemFontOfSize:20]];
        [cell sizeThatFits:CGSizeMake(cell.bounds.size.width, 100)];
    }

return cell;

}
[/code]


#8

I had similar concerns and I thought about doing the work in ItemViewController to leave BNRItemStore unchanged. Though I didn’t do it and went with the other solution (2 NSArray in BNRItemStore as @syndrome suggested).

Why? Performance! tableView:cellForRowAtIndexPath: will get called a lot, like a lot a lot! So you’ll want to make that method as fast as possible. Do an NSLog in tableView:cellForRowAtIndexPath: with 500 items and you’ll see what I mean. Also scroll around a bit. You probably won’t feel any performance changes but you’ll see the potential problem with heavier objects when doing the hard work in that method (as proposed by @benne90)!

Of course the 2 Array solution raises other problems like what happens if you have more sections, like one for every 10$.

With all this in mind I think the NSPredicate solution by @BryanLuby would be the best in a real world example.

Anyway, just my 2cents!

Cheers
Simon

PS: thanks for the hint! [quote=“machouinard”]what I did is replace rand() with arc4random() (in BNRItem.m) and it generates different random items each time.[/quote]


#9

Hi
Here’s the solution I came up with. Big thanks to BryanLuby for the predicates direction. That’ll help me a lot in the future. I’d appreciate any feedback re tidying up parts of this. I wanted to set up the data for the table in the init method (is that an appropriate place?) before I went ahead with creating the table.

Declare the table data array:

@implementation ItemsViewController { NSArray *tableData; }

Set up the array in the init method using BryanLuby’s predicates solution:

- (id) init { self=[super initWithStyle:UITableViewStyleGrouped]; if (self){ for (int i = 0; i<5; i++) { [[BNRItemStore sharedStore] createItem]; } NSPredicate *predicate; predicate = [NSPredicate predicateWithFormat:@"valueInDollars <=50"]; NSArray *under = [[[BNRItemStore sharedStore] allItems] filteredArrayUsingPredicate:predicate]; predicate = [NSPredicate predicateWithFormat:@"valueInDollars >50"]; NSArray *over = [[[BNRItemStore sharedStore] allItems] filteredArrayUsingPredicate:predicate]; tableData = [[NSArray alloc] initWithObjects:under, over, nil]; } return self; }

Count and return the number of objects in tableData

- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView { return [tableData count]; }

Count and return the number of objects within each object at index corresponding to the section - will admit this was a long shot

- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [[tableData objectAtIndex:section] count]; }

Finally, to get the description for the cell:

[code]- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"];    
if (!cell) cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"UITableViewCell"];      

NSArray *sectionArray = [tableData objectAtIndex:[indexPath section]]; // line corrected thanks to @Bario006
BNRItem *p = [sectionArray objectAtIndex:indexPath.row];
[[cell textLabel] setText:[p description]];

return cell;

}
[/code]

Please take this apart to improve it if needs be. I keep slipping in and out of dot notation which probably isn’t good practise.
Steve


#10

@Dan my thinking was the same, I wanted to keep the BNRItemStore separate and put the code to create the two separate arrays in the init of ItemsViewController, just as Steve has above.

I didn’t know about the predicate thing until reading the stuff above, but now I’m sure it’ll come in handy for other things. I just used a straight forward if statement when the items were being created, and if their value was above 50 put them straight into the expensive arrays. What did get confusing was the amount of nested method calls I was doing. I’m sure they’s a neater way to do it.

@Steve I don’t know if I’m missing something though. In your code you create another array in the cellForRow… method, from the tableData arrays you’d created earlier and then create a new item from it. I just called on the items direct nesting the method calls and using the objectAtIndex method, and I’m worried I’ve missed something about calling those items direct and that I should be creating new pointers like you’ve done. Is that why you did it, to protect the original variables?

I still haven’t quite got my head around the different ways to access objects and why some ways are ‘dangerous’. I’ll be revising the getter/setter chapter I think :slight_smile:

[code]- (id)init
{

//Call the superclasses designated initialiser
self = [super initWithStyle:UITableViewStyleGrouped];

if(self){
    
    expensiveItems = [[NSMutableArray alloc] init];
    cheapItems = [[NSMutableArray alloc] init];
    
    for (int i = 0; i < 5; i++){
        [[BNRItemStore sharedStore] createItem];
        
        if([[[[BNRItemStore sharedStore] allItems] objectAtIndex:i] valueInDollars] >50){
            [expensiveItems addObject:[[[BNRItemStore sharedStore] allItems] objectAtIndex:i]]; 
        }else{
            [cheapItems addObject:[[[BNRItemStore sharedStore] allItems] objectAtIndex:i]];
        }
        
    }
}

return self;

}[/code]

Then in the cellForRowAtIndexCode put in in like this, after declaring some constants for the section numbers, kExpensiveItems being 0 and kCheapItems being 1.

[code]-(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, create a new one
if (!cell) {
    cell = [[UITableViewCell alloc]
            initWithStyle:UITableViewCellStyleDefault
            reuseIdentifier:@"UITableViewCell"];
}


switch (indexPath.section) {
    case kExpensiveItems:
        [[cell textLabel] setText:[[expensiveItems objectAtIndex:[indexPath row]] description]];
        break;
    
    case kCheapItems:
        [[cell textLabel] setText:[[cheapItems objectAtIndex:[indexPath row]] description]];
        break;
        
    default:
        [[cell textLabel] setText:@"Unknown"];
        break;
}

return cell;

}[/code]


#11

HI @Dario006, you’re right. Thanks. My spider-sense was tingling when I wrote that line but I couldn’t see why.

I’ve now replaced

with

I’m in the same place as you when it come to the different ‘safe’ ways to access objects. Guess I’ll figure it out over the next 100 hours or so… :open_mouth:
Thanks again, Steve


#12

@BryanLuby : Great solution. I learned about NSPredicate and I think it might be really useful.
I was wondering too how to provide a clear and scalable answer to that challenge.


#13

Thanks @BryanLuby and @sjk1000 for your solutions. Together they helped me better understand how to work with sections and predicates as well as figure out a way to make this solution scalable.


#14

The use of predicate promotes good abstraction and clean code. Thanks for sharing it. :wink:


#15

a


#16

I worked out this solution before I saw the forum here grr…Predicates would have been much easier! The below is a solution if you do not want to use predicates yet / don’t want to create two arrays. For simplicity’s sake I have just hardcoded the sections = 2. Let me know what you think!

here are the methods in BNRItemStore.m

[code]-(NSMutableArray *) findExpensiveItems
{
NSMutableArray *expensiveItems=[[NSMutableArray alloc] init];
for (int i=0; i<[allItems count]; i++){
if([[allItems objectAtIndex:i]valueInDollars]>50)
{
[expensiveItems addObject:[allItems objectAtIndex:i]];
}
}
return expensiveItems;
}

-(NSMutableArray *) findCheapItems
{
NSMutableArray *cheapItems=[[NSMutableArray alloc] init];
for (int i=0; i<[allItems count]; i++){
if([[allItems objectAtIndex:i]valueInDollars]<=50)
{
[cheapItems addObject:[allItems objectAtIndex:i]];
}
}
return cheapItems;
}[/code]

ItemsViewController.m - you’ll see that I’ve also included the solution to the Silver challenge here

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

-(NSString *) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if (section ==0){return @“Greater than $50”;}
else {return @“Less than $50”;}
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section==0)
{return [[[BNRItemStore sharedStore] findExpensiveItems]count] +1;}
else
{return [[[BNRItemStore sharedStore] findCheapItems] count] +1;}
}

-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//create an instance of UITableViewCell with default appearance
//check for reusable cell first
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@“UITableViewCell”];

if(!cell){
    cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"UITableViewCell"];
}

//section 0
if([indexPath section] == 0)
    {if([indexPath row]<[[[BNRItemStore sharedStore] findExpensiveItems] count])
        {BNRItem *p = [[[BNRItemStore sharedStore] findExpensiveItems] objectAtIndex:[indexPath row]];
            [[cell textLabel] setText:[p description]];}
    else {[[cell textLabel] setText:@"No more items!"];}
    }
//section 1
else         
{if([indexPath row]<[[[BNRItemStore sharedStore] findCheapItems] count])
{BNRItem *p = [[[BNRItemStore sharedStore] findCheapItems] objectAtIndex:[indexPath row]];
    [[cell textLabel] setText:[p description]];}
else {[[cell textLabel] setText:@"No more items!"];}
}


return cell;

}
[/code]


#17

[quote=“BryanLuby”]I used an alternate way for this challenge using NSPredicate. Found this from the BNR iOS Programming 2nd Edition forums developer.apple.com/library/ios/ … cates.html. NSArray has a filteredArrayUsingPredicate: method. Using this method along with the predicates allows you to parse the allItems array without having to create two separate arrays. Not sure how this stacks up performance-wise, but it keeps the code simple without having to make changes to the data store class.
[/quote]

I too really liked BryanLuby’s approach using predicates. Was wondering though, how did you deal with setting up the two sections? Did you figure out a scalable way of doing this or just have numberOfSectionsInTableView: return 2 in ItemsViewController.m?


#18

[quote=“emmet0r”]
I too really liked BryanLuby’s approach using predicates. Was wondering though, how did you deal with setting up the two sections? Did you figure out a scalable way of doing this or just have numberOfSectionsInTableView: return 2 in ItemsViewController.m?[/quote]
Since the challenge specifically requested 2 sections, I just used: - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 2; }
If your data hierarchy is more complex/dynamic, then it probably won’t be that simple. For example, when you have an array of nested multiple arrays. The top level array might correspond to sections, so you could get a count of that array for numberOfSectionsInTableView. The next level array might correspond to rows, so you could use a count of that array for numberOfRowsInSection, etc.


#19

Thanks, that’s what I was thinking too! Just wanted to make sure I wasn’t overcomplicating things by thinking so :slight_smile:


#20

So I wanted to do it without altering the other files and without learning about predicates. (who has the time?!) So all of this takes place in ItemViewController.m.
So obviously we have this line in there: - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 2; }
We could make this part variable but there is no need to now.

Ok so now we want to enumerate through the allItems array to see how many rows go in each section. Some conditionals make quick work of this part.

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { int sectionCount = 0; // Our counter integer for (BNRItem *item in [[BNRItemStore sharedStore] allItems]) { if ([item valueInDollars] > 50) sectionCount++; } int returnValue; if (section == 0) { returnValue = sectionCount; } else { returnValue = [[[BNRItemStore sharedStore] allItems] count] - sectionCount; } return returnValue; }

Now we just need a clever way to put the items in the cells they belong in. I didn’t want to sort or make two arrays. I instead used enumeration and a counting variable to check to see if the item both goes in the section indexPath is sending and also if it needs to keep looking for the next item if the one it is checking has already been used. If the value is more than $50 and the [indexPath row] equals how many over $50 items we have already enumerated through, then it is the one we are looking for. I hope that makes sense. Here is the code:

- (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"];
    }
    // Make the variables we will need for the enumeration
    BNRItem *p = nil;
    int sectionCount = 0;

    if ([indexPath section] == 0) { // Check the section, this is for over $50 items
        for (BNRItem *item in [[BNRItemStore sharedStore] allItems]) {
            if ([item valueInDollars] > 50) { // If its over $50 and..
                
                if ([indexPath row] == sectionCount) { // ...we have already looked over the ones that are in the cells before it...
                    p = item;  // ...then it is the one we want to pull the description from.
                }
                sectionCount++; // This adds up how many rows we have been through that are over $50.
            }
        }
    } else {
        for (BNRItem *item in [[BNRItemStore sharedStore] allItems]) {
            if ([item valueInDollars] <= 50) {
                
                if ([indexPath row] == sectionCount) {
                    p = item;
                }
                sectionCount++;
            }
        }
    }
    
    [[cell textLabel] setText:[p description]];
    
    return cell;
}

Works for me, it may be a little bit slower to implement on the hardware side but it doesn’t take any modification to any other files.