CellForRowAtIndexPath in a nib project - ios

I have implemented the CellForRowAtIndexPath method in my project that works.
It looks like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"StackTableViewCell";
Target *target = [self.fetchedResultController objectAtIndexPath:indexPath];
StackTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell)
{
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"StackTableViewCell" owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];
}
cell.cellLabel.text = target.body;
cell.cellLabel.font = [UIFont fontWithName:#"Candara-Bold" size:20];[UIFont fontWithName:#"Candara-Bold" size:20];
// Configure the cell...
return cell;
}
but there is something that bothers me and it's that I don't really understand what happened in this part (I took it from some tutorial):
if (!cell)
{
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"StackTableViewCell" owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];
}
can someone please help me understand this?
thanks!

If the table view doesn't have a cell available to re-use, load the objects that exist in StackTableViewCell.xib. Assume that the first one you find that's defined at the top level can be instantiated as the type of cell that you want.

if (!cell)
{
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"StackTableViewCell" owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];
}
You are trying to load cell from nib when cell is nil.
Usually, I do like this:
in ViewDidLoad
[self.tableView registerNib:[UINib nibWithNibName:#"StackTableViewCell" bundle:nil] forCellReuseIdentifier:cellIdentifier];
so in tableView:cellForRowAtIndexPath method you can get cell and you will not need to check if it nil or not, because it will always return cell
StackTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

Related

Request keys from tableview and show them in Custom cell

I have a tableview, the tableview picks up data from a dictionary and shows it in the tableview. I also have a Custom tableview cell. The data which is displayed in the tableview, I need to show that in the custom tableview cell.
This is the code from my tableview:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
HistoryTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"HistoryViewTableCell"];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"HistoryViewTableCell" owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];
}
NSDictionary * tempDictionary = [tableData objectAtIndex:indexPath.row];
cell.textLabel.text = [tempDictionary objectForKey:#"PickupAddress"];
return cell;
}
I need to show this data in my custom tableview cell. If it's not very clear, please ask and I will try to explain the best I can.
You can override 'new' method in order to load cell from xib. Try this one
+(instancetype) new
{
id cell = nil;
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:nil options:nil];
for(id currentObject in topLevelObjects)
{
if([currentObject isKindOfClass:[self class]])
{
cell = currentObject;
break;
}
}
NSParameterAssert(cell);
return cell;
}

How Can i Add multiple customCells (in my case its 3) in a TableView

I am creating a demo Application in which i need 3 customCells in a tableView. I am able to add a first customCell in all three rows, but when i add 3 cells application crash.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Create Rows in a tableView
return 3;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"customCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
// First CustomCell
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"FirstCustomCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
if (indexPath.row ==1) {
// Second CustomCell
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
if (indexPath.row == 2) {
// Third CustomCell
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"PhoneTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:1];
}
}
return cell;
}
when I run the application it crashes This is the error message : Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
The problem is here
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"PhoneTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:1];
^^^
It should be
cell = [nib objectAtIndex:0];
problem is cell = [nib objectAtIndex:1]; It must be always cell = [nib objectAtIndex:0]; because there will be only one Nib of that name
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"customCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
// First CustomCell
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"FirstCustomCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
if (indexPath.row ==1) {
// Second CustomCell
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
if (indexPath.row == 2) {
// Third CustomCell
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"PhoneTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
}
return cell;
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (Your_Condition==1) {
DoctorListCell *cell = (DoctorListCell *)[tableView dequeueReusableCellWithIdentifier:#"DoctorListCell"];
if(cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"iPhone_DoctorListCell"
owner:self
options:nil];
cell = (DoctorListCell *)[nib objectAtIndex:0];
}
return cell;
}
else if(your_Condition==2)
{
ArticleListCell *cell = (ArticleListCell *)[tableView dequeueReusableCellWithIdentifier:#"ArticleListCell"];
if(cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"iPhone_ArticleList"
owner:self
options:nil];
cell = (ArticleListCell *)[nib objectAtIndex:0];
}
return cell;
}
else if(your_condition==3)
{
AnswersCell *cell = (AnswersCell *)[tableView dequeueReusableCellWithIdentifier:#"AnswersCell"];
if(cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"iPhone_AnswersCell" owner:self options:nil];
cell = (AnswersCell *)[nib objectAtIndex:0];
}
return cell;
}
return nil;
}

how to show different custom cell in a table view in ios

1. in my method in write code example given below -
(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
static NSString *simpleTableIdentifier2 = #"SimpleTableCell2";
if (indexPath.row== 0) {
SimpleTableCell *cell = nil;
cell=(SimpleTableCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
}
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
if (indexPath.row == 1) {
SimpleTableCell2 *cell2 = nil;
cell2=(SimpleTableCell2 *) [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier2];
}
if (cell2 == nil)
{
NSArray *nib2 = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableCell2" owner:self options:nil];
cell2 = [nib2 objectAtIndex:0];
}
cell.nameLabel.text = [tableData objectAtIndex:indexPath.row];
cell.thumbnailImageView.image = [UIImage imageNamed:[thumbnails objectAtIndex:indexPath.row]];
cell.prepTimeLabel.text = #"detail";// [prepTime objectAtIndex:indexPath.row];
//cell.imageView.image = [UIImage imageNamed:#"creme_brelee.jpg"];
cell2.nameLabel.text = [tableData objectAtIndex:indexPath.row];
return cell;
}
can any one help me am i write correct code becoz it will give an error
the error is use of undeclear identifier cell and cell2
i dont understand what is this error
it gives the error after making cell2 before cell2 it works perfectly
help me
thanks
It is giving the error because you have declared it like this:
if (indexPath.row== 0) {
SimpleTableCell *cell = nil;
cell=(SimpleTableCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
}
and you are using the cell variable outside the local scope of this condition.
Do this:
SimpleTableCell *cell = nil;
if (indexPath.row== 0)
{
cell=(SimpleTableCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
}
Also make sure that you have imported the header SimpleTableCell.h.
Hope that helps!
if (indexPath.row == 1) {
SimpleTableCell2 *cell2 = nil;
cell2=(SimpleTableCell2 *) [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier2];
//This is ok
cell2.nameLabel.text = [tableData objectAtIndex:indexPath.row];
}
//No you cant access outside
cell2.nameLabel.text = [tableData objectAtIndex:indexPath.row];
Here, you have declared cell2 inside the if block. So you can use this variable in this scope only. When you try to access cell2 outside, you will get use of undeclared error.
Undeclared identifier means that you didn't register cell class.
You should do that in viewDidLoad:
-(void)viewDidLoad
{
[self.tableView registerClass:[SimpleTableCell class] forCellReuseIdentifier:#"SimpleTableCell"];
[self.tableView registerClass:[SimpleTableCell2 class] forCellReuseIdentifier:#"SimpleTableCell2"];
}
However, NSStringFromClass approach is better when dealing with cell identifiers:
-(void)viewDidLoad
{
[self.tableView registerClass:NSStringFromClass([SimpleTableCell class]) forCellReuseIdentifier:#"SimpleTableCell"];
[self.tableView registerClass:NSStringFromClass([SimpleTableCell2 class]) forCellReuseIdentifier:#"SimpleTableCell2"];
}
If you didn't register a cell class, dequeueReusableCellWithIdentifier can return nil, as specified in the docs:
This method dequeues an existing cell if one is available or creates a new one
using the class or nib file you previously registered. If no cell is available
for reuse and you did not register a class or nib file, this method returns nil.
Additional note: keep your view controller methods as slim as possibile.
you could try these codes:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath (NSIndexPath *)indexPath{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
static NSString *simpleTableIdentifier2 = #"SimpleTableCell2";
if (indexPath.row== 0) {
SimpleTableCell *cell = nil;
cell = (SimpleTableCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil){
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.nameLabel.text = [tableData objectAtIndex:indexPath.row];
cell.thumbnailImageView.image = [UIImage imageNamed:[thumbnails objectAtIndex:indexPath.row]];
cell.prepTimeLabel.text = #"detail";// [prepTime objectAtIndex:indexPath.row];
//cell.imageView.image = [UIImage imageNamed:#"creme_brelee.jpg"];
return cell;
}
SimpleTableCell2 *cell2 = nil;
if (indexPath.row == 1) {
cell2 = (SimpleTableCell2 *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier2];
if (cell2 == nil){
NSArray *nib2 = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableCell2" owner:self options:nil];
cell2 = [nib2 objectAtIndex:0];
}
cell2.nameLabel.text = [tableData objectAtIndex:indexPath.row];
}
return cell2;
}
if (indexPath.row== 0) {
SimpleTableCell *cell = nil;
cell=(SimpleTableCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
return cell;
}
if (indexPath.row == 1) {
SimpleTableCell2 *cell2 = nil;
cell2=(SimpleTableCell2 *) [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier2];
if (cell2 == nil)
{
NSArray *nib2 = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableCell2" owner:self options:nil];
cell2 = [nib2 objectAtIndex:0];
}
return cell2;
}
UITableViewCell *commonCell = [tableView dequeueReusableCellWithIdentifier:#"commonToALL"];
if (commonCell == nil) {
commonCell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"commonToALL"];
}
return commonCell;
Try This. This will create two specific cell for index 0 and 1 while two general Cells for remainder as you have 4 rows.
You'd better check you custom cell's tag in SimpleTableCell.xib
whether the tag is 0
and just one custom cell could work like:
(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.nameLabel.text = [tableData objectAtIndex:indexPath.row];
cell.thumbnailImageView.image = [UIImage imageNamed:[thumbnails objectAtIndex:indexPath.row]];
cell.prepTimeLabel.text = #"detail";// [prepTime objectAtIndex:indexPath.row];
//cell.imageView.image = [UIImage imageNamed:#"creme_brelee.jpg"];
if (indexPath.row == 1) {
[cell.thumbnailImageView.image setHidden:Yes];
[cell.prepTimeLabel.text setHidden:Yes];
}
return cell;
}

UITableView reuse cells (stop duplicating)

This is my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"simpleTable";
profileCellViewController *cell = [self.myTable dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"simpleTable" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
//loading data
...
...
...
cell.name.text = name;
cell.time.text = time;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
I know the problem is in the if (cell==nil) part
but really don't know hoe I can solve this...
every time im back to this viewcontroller tab the cells duplicated

How to properly use "dequeueReusableCellWithIdentifier:" with multiple identifiers?

I have a Core Data backed table view, that show a list of editable fields, for different field types I have different UTableViewCells with different cell identifiers. When I scroll too quickly in the simulator or try to "bounce" past the last cell, I get a crash, saying that UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath. The whole problem goes away if I remove the dequeueReusableCellWithIdentifier: steps. Which means my table view is less efficient. I'm at most using 20 fetched objects (more along the lines of 8-10) in my table view, so the inefficiency might be a minor issue. I'd just like to know if I'm doing something the wrong way.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Field *aField = [self.fetchedResultsController objectAtIndexPath:indexPath];
static NSString *CellIdentifier = #"Cell";
static NSString *ChoiceIdentifier = #"ChoiceCell";
static NSString *SwitchIdentifier = #"SwitchCell";
UITableViewCell *cell;
if ([aField.fieldType isEqualToString:#"choice"] || [aField.fieldType isEqualToString:#"date"] || [aField.fieldType isEqualToString:#"multiChoice"] ) {
NSLog(#"ChoiceCell");
cell = [tableView dequeueReusableCellWithIdentifier:ChoiceIdentifier];
if (cell == nil) {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[[NSBundle mainBundle] loadNibNamed:#"ChoiceTableViewCell-iPad" owner:self options:nil];
} else {
[[NSBundle mainBundle] loadNibNamed:#"ChoiceTableViewCell" owner:self options:nil];
}
}
} else if ([aField.fieldType isEqualToString:#"boolean"]){
NSLog(#"SwitchCell");
cell = [tableView dequeueReusableCellWithIdentifier:SwitchIdentifier];
if (cell == nil) {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[[NSBundle mainBundle] loadNibNamed:#"SwitchTableViewCell-iPad" owner:self options:nil];
} else {
[[NSBundle mainBundle] loadNibNamed:#"SwitchTableViewCell" owner:self options:nil];
}
}
} else {
NSLog(#"Cell");
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[[NSBundle mainBundle] loadNibNamed:#"EditableTableViewCell-iPad" owner:self options:nil];
} else {
[[NSBundle mainBundle] loadNibNamed:#"EditableTableViewCell" owner:self options:nil];
}
}
}
cell = editableCell;
self.editableCell = nil;
// Configure the cell...
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
Additional Details: The editableCell is being set as in each of the NIBs that correspond to the custom cells. I tried more directly setting this by saying
dynamicCell = [[[NSBundle mainBundle] loadNibNamed:#"ChoiceTableViewCell-iPad" owner:self options:nil] objectAtIndex:0];
but still had the same problem. It should never return nil. The all the NIBs are being loaded as long as I don't scroll too fast. I've double and triple checked the NIB names to make sure.
Here's the updated working code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Field *aField = [self.fetchedResultsController objectAtIndexPath:indexPath];
static NSString *CellIdentifier = #"Cell";
static NSString *ChoiceIdentifier = #"ChoiceCell";
static NSString *SwitchIdentifier = #"SwitchCell";
if ([aField.fieldType isEqualToString:#"choice"] || [aField.fieldType isEqualToString:#"date"] || [aField.fieldType isEqualToString:#"multiChoice"] ) {
NSLog(#"ChoiceCell");
dynamicCell = [tableView dequeueReusableCellWithIdentifier:ChoiceIdentifier];
if (dynamicCell == nil) {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[[NSBundle mainBundle] loadNibNamed:#"ChoiceTableViewCell-iPad" owner:self options:nil];
} else {
[[NSBundle mainBundle] loadNibNamed:#"ChoiceTableViewCell" owner:self options:nil];
}
}
} else if ([aField.fieldType isEqualToString:#"boolean"]){
NSLog(#"SwitchCell");
dynamicCell = [tableView dequeueReusableCellWithIdentifier:SwitchIdentifier];
if (dynamicCell == nil) {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[[NSBundle mainBundle] loadNibNamed:#"SwitchTableViewCell-iPad" owner:self options:nil];
} else {
[[NSBundle mainBundle] loadNibNamed:#"SwitchTableViewCell" owner:self options:nil];
}
}
} else {
NSLog(#"Cell");
dynamicCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (dynamicCell == nil) {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[[NSBundle mainBundle] loadNibNamed:#"EditableTableViewCell-iPad" owner:self options:nil];
} else {
[[NSBundle mainBundle] loadNibNamed:#"EditableTableViewCell" owner:self options:nil];
}
}
}
UITableViewCell *cell;
cell = dynamicCell;
self.dynamicCell = nil;
// Configure the cell...
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
Looks like the problem is with:
cell = editableCell
if editableCell is nil your app will crash. I assume you intend editableCell to be set by loadNibNamed:. It is not set if you dequeue a cell.

Resources