Reputation: 17651
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!)
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
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
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
Reputation: 7440
You can't use 2 return statements, only first one will be executed;
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