dequeueReusableCellWithIdentifier: Remembering State of Cell

958 Views Asked by At

I've embedded horizontal table views inside of table cells (ala the Pulse Reader). The interesting behavior that I'm getting is that dequeueReusableCellWithIdentifier: seems to be correctly remembering the offset of the embedded table views, without me doing anything. But there are two flavors to "remembering"

First (expected)

I create a table with 100 sections and 1 row per section. Each cell (each section) gets an embedded table view that I force to have 100 rows and 1 section. When I scroll the vertical table view, cells are reused (checked by looking at the instance names of the cells after dequeueReusableCellWithIdentifier:

VerticalTableViewCell *cell = (VerticalTableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

If I scroll the first table view cell's embedded table view to the right, say 10.5 cells, when I scroll down a couple cells in the vertical table view, the reused table cell has its embedded table view offset by those 10.5 cells. This makes sense, the cell was just reused and I didn't reset any offsets. Let's say that reused cell was the 7th row. If I now slide the 7th row's embedded table view (this is the same embedded table view as row one, due to the reuse) to position 20, when I go to the top of the vertical table view that embedded table view (which I had originally moved to 10.5), is now at 20. Again, expected, those table cells are the same. Just reused.

Second (desired, but have no idea how it works)

Now I fill in my real data (instead of just printing

 [cell.textLabel setText:[NSString stringWithFormat: @"here: %d", indexPath.row]]; 

to the cell.

Now, all of a sudden, my embedded table views DO remember where they were. I once again ensure the cells are being reused (same method as above). But this time, when I scroll the first embedded table view (to position 10.5) and scroll down to the seventh row, the seventh row is at its starting point. When I scroll the first row back into view, it's right where I left it.

This is using Xcode 4.2 and iOS 5.0. Is there something smart that dequeueReusableCellWithIdentifier: does?

In old school (pre-iOS 5.0), I would have checked the

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

if (cell == nil) 
{
   cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
}

bits of logic to see what was happening, but with StoryBoards those are no longer necessary.

The 2 sample projects that behave differently are kind of big, but if there's any relevant code you'd like to see, let me know.

Sorry to be so vague, I'm just trying to grasp exactly whats going on with the memory management of these table views.

All the connections are via IBOutlets and made in the StoryBoard.

Thanks!

First Vertical Table View Controller

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
//#warning Potentially incomplete method implementation.
// Return the number of sections.
return 100;
}

 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
 {
//#warning Incomplete method implementation.
// Return the number of rows in the section.
return 1;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 {
static NSString *CellIdentifier = @"PlayerCell";

PlayerCell *cell = (PlayerCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];


// Configure the cell...

cell.games = [NSMutableArray arrayWithCapacity:1];
if(indexPath.section <40){
    //[cell.textLabel setText:[NSString stringWithFormat:@"h343: %d", indexPath.section]];
}

CGAffineTransform rotateTable = CGAffineTransformMakeRotation(-M_PI_2);
cell.htv.transform = rotateTable;
cell.htv.frame = CGRectMake(0, 0, 320, 120);

return cell;
 }

First Horizontal Table View Delegate/Data Source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

// Return the number of sections.
return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

// Return the number of rows in the section.
return 100;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath   *)indexPath
{
static NSString *CellIdentifier = @"Cell";

//UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UITableViewCell *cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

// Configure the cell...

CGAffineTransform rotateImage = CGAffineTransformMakeRotation(M_PI_2);
cell.transform = rotateImage;

//[cell.myLabel setText:[NSString stringWithFormat:@"%d", indexPath.row]];

[cell.textLabel setText:[NSString stringWithFormat: @"here: %d", indexPath.row]]; 
return cell;
}

Second Vertical Table View Controller

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

// Return the number of sections.
return [self.leagues count];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

// Return the number of rows in the section.
return 1;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath     *)indexPath
{
static NSString *CellIdentifier = @"VerticalTableViewCell";




VerticalTableViewCell *cell = (VerticalTableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

NSLog(@"Cell: %@ for index: %d", cell, indexPath.section);


cell.games = [self.leagues objectAtIndex:indexPath.section];

CGAffineTransform rotateTable = CGAffineTransformMakeRotation(-M_PI_2);
cell.horizontalTableView.transform = rotateTable;
cell.horizontalTableView.frame = CGRectMake(0, 0, 320, 120);
// Configure the cell...



cell.selectionStyle = UITableViewCellSelectionStyleNone;

cell.section = indexPath.section;

return cell;
}

Second Horizontal Table View Delegate/Data Source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

// Return the number of sections.
return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

// Return the number of rows in the section.
return [self.games count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 {
static NSString *CellIdentifier = @"HorizontalTableViewCell";

//UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
GameTableCell *cell = (GameTableCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

// Configure the cell...

CGAffineTransform rotateImage = CGAffineTransformMakeRotation(M_PI_2);
cell.transform = rotateImage;

//[cell.myLabel setText:[NSString stringWithFormat:@"%d", indexPath.row]];

NSDictionary *game = [self.games objectAtIndex:indexPath.row];
[cell.homeTeamLogo setImage:[UIImage imageNamed:[NSString stringWithFormat:@"%@",[game objectForKey:@"LogoImage_HomeTeam"]]]];
[cell.visitingTeamLogo setImage:[UIImage imageNamed:[NSString stringWithFormat:@"%@",[game objectForKey:@"LogoImage_VisitingTeam"]]]];
[cell.homeTeamName setText:[NSString stringWithFormat:@"%@", [game objectForKey:@"AbbreviatedName_HomeTeam"]]];
[cell.visitingTeamName setText:[NSString stringWithFormat:@"%@", [game objectForKey:@"AbbreviatedName_VisitingTeam"]]];

NSDictionary *gameTime = [game objectForKey:@"GameTime"];
NSString *minutes = [NSString stringWithFormat:@"%@", [gameTime objectForKey:@"Minutes"]];
if([minutes length]==1){
    minutes = @"00";
}
NSString *timeOfGame = [NSString stringWithFormat:@"%@:%@",[gameTime objectForKey:@"Hours"], minutes];

[cell.gameTime setText:timeOfGame];

return cell;
}
1

There are 1 best solutions below

0
On

My fault.

I was saving the state of the the embedded Table View.

FYI: I was using the tableView.contentOffset (in case anybody needs to do this later).

Whoops.