Challenge Problem: Section


#1

I am reposting this question, hoping to get some responses. I am at a loss as to how to display possession items under value $50 in one section and over $50 in another section.

Here is what I am doing in my implementation section.

@implementation ItemsViewController

-(id) init
{
	// Call the superclass's designated initializer
	[super initWithStyle:UITableViewStyleGrouped];
	
	// Create an array of 10 random possessions objects
	possessions = [[NSMutableArray alloc] init];
	possessions2 = [[NSMutableArray alloc] init];
	
	for (int i=0; i <5; i++) {
		if ([[Possesions randomPossession] valueInDollars] < 50) {
			[possessions1 addObject:[Possesions randomPossession]];

		}
		else {
			[possessions2 addObject:[Possesions randomPossession]];

		}

		//z[possessions addObject:[Possesions randomPossession]];
	}
	return self;
}

And, to create 2 sections, I am using

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

Could you please give me some directions on how to assign the correct entries to correct section?

Thank you.


#2

Hi,

tableviews are populated by asking the datasource a series of questions about what to display.

How many sections ? - which you’ve addressed in the numberOfSectionsInTableView “return 2”

then

How many rows in section 0 ?
and then a bit later
How many rows in section 1 ?

So you will need to implement numberOfRowsInSection:(NSInteger)section to answer these questions
{
// Which section am I being asked about
if (section == 0)
return [possessions1 count];
else //Must be section 1
return [possessions2 count];
}

and you also need to answer:
"What cell should I use for Section n Row n ? - This will be asked for each cell displayed

so in the method cellForRowAtIndexPath:(NSIndexPath *)indexPath
you can say

if ([indexPath section] == 0)
[[cell textLabel] setText:[[possessions1 objectAtIndex:[indexPath row]] description]];
else //Must be section 1
[[cell textLabel] setText:[[possessions2 objectAtIndex:[indexPath row]] description]];

Hopefully that helps - if you’re still struggling let me know.

Gareth


#3

Thank you for the clear answer. That helped quite a bit! Thanks again.


#4

Hi,

Doing this from memory so could be way off here.

Each time [Possession randomPossession] is executed it creates a new possession so the code is checking the value of a possession but then generating a brand new one to put in the array.

So you will need to store it first. Something along the lines of…

Possession *newPossession = [Possession randomPossession];

if ([newPossession valueInDollars] > 50)
[possessions addObject:newPossession];
else
[under50 addObject:newPossession];

HTH

Gareth


#5

GarethR:

I solved the Challenge using more or less the solution you posted. One issue I am having, though, is that if I try to scroll way down or way up (such that it should bounce back into place because I am scrolling beyond the list), the app crashes. I’ve put in plenty of NSLog events to try to track this down, but I can see to figure out what’s up. It’s almost like it is trying to make a new cell or pull additional info for a cell that is not there. What should I check, or how can I troubleshoot this kind of problem?

Thanks!
Paul


#6

Hi Paul,

First thing that springs to mind is whether you’re returning the correct row count for the relevant section. If not you’ll get a NSRangeException for exceeding the array bounds.

If that’s the case then check that your two arrays are consistently used in the numberOfRowsInSection and cellForRowAtIndexPath methods.

It can help to #define these to make it easier to spot.

#define kpossessionsUnderFifty 0
#define kpossessionsOverFifty 1

then instead of
if (section == 0)

you can say
if (section == kpossessionsUnderFifty)
return [possessionsUnderFifty count];

and

if ([indexPath section] == kpossessionsUnderFifty)
[[cell textLabel] setText:[[possessionsUnderFifty objectAtIndex:[indexPath row]] description]];

If this isn’t the problem then let me know what the console’s displaying after the crash.

Gareth


#7

Well, it is definitely not an Out of Range Exception. I logged each count to the Console, and I am getting 6 for [expensivePossessions count] and 4 for [cheapPossessions count].

One addition observation I just noticed is that the crashes as the tableview is snapping back into position. That is, let’s say I drag it way up… the app will crash immediately after I let go of it. The same thing happens if I drag it way down and let go.

One thing I just noticed is that this happens when I drag it far enough for one cell to disappear, and when it comes back onto the screen, usually it is populated with something like “ca.lproj” or “file://blahblah”. So yes, it is pulling from somewhere outside of the array. Or rather, it is missing the index and hitting some place in memory that it shouldn’t. I am guessing that occasionally, it hits something that it really shouldn’t and that’s when it crashes.

I’m still looking into this, but I thought I’d share.


#8

Hmmm, it sounds like somethings going wrong around the dequeueReusableCell area as this starts coming into play when cells disappear off the screen.

Good Luck

Gareth


#9

Yeah, i definitely think it’s something with my reusable cells. I’ve been playing around with it for a while this morning, and can’t seem to get any useful feedback from the console. Here is my tableView:cellForRowAtIndexPath method. Let me know if you see anything off-base.

[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"] autorelease];
}

//Set the text on the cell with the description of the possesion that is at the nth index of possessions,
//where n  = row this cell will appear in on the tableview
if ([indexPath section]==0) {
	[[cell textLabel] setText:[[cheapPossessions objectAtIndex:[indexPath row]] description]];
}
if ([indexPath section]==1) {
	[[cell textLabel] setText:[[expensivePossessions objectAtIndex:[indexPath row]] description]];
}
return cell;

}[/code]

I know my two arrays are set up properly, and when I reference the indexPath row, that is correct. I’m just not sure how it is pulling data from the wrong place when it tries to reuse a reusable cell.


#10

Paul,

Can’t see anything wrong there.

Post the rest of your code if you’re at a loss.

Gareth


#11

I had a similar problem and I fixed it, but I’m not sure how or why. When I stopped autoreleasing the temporary possession object I created in init, the program stopped crashing. Shouldn’t I be autoreleasing those objects? Doesn’t the NSMutableArray retain those after addObject?

I don’t have the exact code in front of me, but it was something like this:


for (int i=1; i<=10; i++)
{
   Possession *tempPossession = [Possession randomPosession];
   if ([tempPossession valueinDollars]>50)
    //add to high price possession array
    [highPriceArray addObject:tempPossession];
    else 
    //low price
    [lowPriceArray addObject:tempPossession];
}

So I thought if I autoreleased tempPossession I would be OK, but I guess not. Earlier in the book (chapter 2 or 3) I thought it said NSMutableArray will retain the object after addObject.

Edit: Forgot to add the debugger was showing an “EXC_BAD_ACCESS” message, which led me to my fix. I’m sure whoever is getting the crashing when scrolling is probably seeing the same thing.


#12

If you had autoreleased (or released) the possession after you added to the array, you’d get a crash.

This is because the possession you are given that you intend to add to the array has already been autoreleased.


#13

I was stuck with

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

instead i was using

- (NSInteger)numberOfSections { return 2; }

I was so stupid. Grrr
Hope this helps anyone who wrote everything else right.