Dancer
Dancer

Reputation: 17651

How to maintain cells with different layouts in one UITableView

Can anyone help me understand what I'm doing wrong with my UITableView please?

I've setup a message list which contains two custom cells - Depending on whether a variable is true or false. I'd like to apply my data to the relevant cell - but what I get is both custom cells on top of one another repeated 3 times as on below (cells in the foreground are not styled by the way - just for example!)

enter image description here

this is my code -

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

    CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier  forIndexPath:indexPath];

    customCellRead *cellRead = [tableView dequeueReusableCellWithIdentifier:CellIdentifierRead forIndexPath:indexPath];

    notifications *n = [self.GPTNotifications objectAtIndex:indexPath.row];

    if (n.read == false) {
        cellRead.readText.text =n.notifMessage;
        cellRead.reDate.text =n.notifDateD;
        cellRead.resub.text = n.notifDateD;

    }
    if (n.read == true) {


       cell.notifTitle.text = n.notifTitleD;
       cell.notifDate.text = n.notifDateD;
       cell.notifMsg.text = n.notifMessage;
    }

// Configure the cell...

    return cell;
    return cellRead;
}

Upvotes: 1

Views: 987

Answers (3)

vikingosegundo
vikingosegundo

Reputation: 52227

return cell;
return cellRead;

in C and all other languages that feature a return statement, any method will be left and terminated when reaching the first return statement, return cellRead; will never be reached.

instead of using one custom cell for 2 different layouts you should use 2.

- (void) viewDidLoad {
   [super viewDidLoad];

   [self.tableView registerClass:[MyCell class] forCellReuseIdentifier:@"Cell"];
   [self.tableView registerClass:[MyReadCell class] forCellReuseIdentifier:@"CellRead"];
}


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

    UITableView *cell;


    notifications *n = [self.GPTNotifications objectAtIndex:indexPath.row];

    if (n.read == false) {
        cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
        MyReadCell *cellRead = (MyReadCell *)cell;
        cellRead.readText.text =n.notifMessage;
        cellRead.reDate.text =n.notifDateD;
        cellRead.resub.text = n.notifDateD;

    }
    if (n.read == true) {
        cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifierRead forIndexPath:indexPath];
        MyCell *myCell = (MyCell *)cell;
        myCell.notifTitle.text = n.notifTitleD;
        myCell.notifDate.text = n.notifDateD;
        myCell.notifMsg.text = n.notifMessage;
    }

    // Configure the cell...

    return cell;
}

Upvotes: 1

Francescu
Francescu

Reputation: 17054

First we have to understand how works the UITableView. Using the delegate pattern it asks the controller which cell it has to display at a given index.

The first way coming in mind is to initialize at the init or viewDidLoad method an array of UITableViewCell instances and to provide the good cell at tableView:cellForRowAtIndexPath:

Basically

- (void)viewDidLoad
self.cells = @[myCell1, myCell2];

- (UITableViewCell *)tableView:cellForRowAtIndexPath:index
return self.cells[index.row];

But you have to keep in mind that list are designed to have potentially a very big number of cells. So Apple designed a way to do this. It is always better to manipulate entities than UI elements. So Apple provide you a way to "recycle" cells. At a given time you have less than 10 cells on the screen.

So when one cell goes out the screen the tableView keep it in memory for later. When one cell comes in the screen you can take one cell in this recycle queue using dequeueReusableCellWithIndentifier:@"MyCell". At the beginning no cell can be found in the queue so it will return nil. So you have to initialize a cell.

static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
//Do initial visual configuration here
cell.textLabel.textColor = [UIColor redColor];
}
// Get entity 
Notification entity = self.GPTNotifications[indexPath.row];
// Configure the according
cell.textLabel.text = entity.x;

return cell;

So for your exact problem, the first thing we have to know is : Do you have 2 distincts tableView or 2 kind of cell according to read property ?

For the second problem your method should be like :

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath     *)indexPath
{
    notifications *n = [self.GPTNotifications objectAtIndex:indexPath.row];
    CustomCell *cell;
    if (n.read)
    {
            static NSString *CellIdentifierRead = @"CellNotifRead";
        cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifierRead];
        if (cell == nil)
            cell = [[CustomCell alloc] init];

        cell.notifTitle.text = n.notifTitleD;
        cell.notifDate.text = n.notifDateD;
        cell.notifMsg.text = n.notifMessage;
    }
    else
    {
            static NSString *CellIdentifier = @"CellNotifUnread";
        cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil)
            cell = [[CustomCell alloc] init];

        cellRead.readText.text =n.notifMessage;
        cellRead.reDate.text =n.notifDateD;
        cellRead.resub.text = n.notifDateD;
    }
    return cell;
}

Upvotes: 3

Novarg
Novarg

Reputation: 7440

  1. You can't use 2 return statements, only first one will be executed;

  2. You should add a check if your cell is nil or not. And if it is, you should initialise it

Default method looks like this:

static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}

// Configure the cell...

return cell;

Upvotes: 2

Related Questions