I am using the code below and getting (Use of undeclared identifier "TableCell")
In the property attribute inspector TableCell is already defined under custom
Any idea?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"TableCell";
TableCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
int row = [indexPath row];
cell.TitleLabel.text = _Title[row];
cell.Desctiptionlabel.text = _Description[row];
cell.ThumbImage.image = [UIImage imageNamed:_Images[row]];
return cell;
}
If you use the dequeueReusableCellWithIdentifier:forIndexPath: method, you must remember to register the identifier with a class or a NIB first.
That code for your class will probably look something like the following in viewDidLoad, perhaps.
[self.tableView registerNib:[UINib nibWithNibName:"TableCell" bundle:nil] forCellReuseIdentifier:CellIdentifier];
Alternatively, you can use the older dequeueReusableCellWithIdentifier: method, but you will have to handle the case that cell will be nil after dequeue and you will need to load the cell from a nib or instantiate a new object manually.
As an aside, the convention in Objective-C development is to use lower camel case class member names and local variables.
Related
I created a UITableViewController of dynamic prototype cells in the Storyboard that can show 3 different custom cells
But I am getting *** Assertion failure in -[UITableView _configureCellForDisplay:forIndexPath:], / which theoretically means that the reuseidentifier I am trying to use in my cellForRowAtIndexPath does not exist but as I am sure I have defined it in my storyboard.
This is my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
HomeOverviewItem *item = [_items objectAtIndex:indexPath.row];
NSLog(#"cell at %#",indexPath);
if([item propCellType] == HomeOverviewItem_HEADER){
CellHomeHeader *cell = (CellHomeHeader *)[tableView dequeueReusableCellWithIdentifier:#"cell_header"];
cell.propLabelName.text = item.propName;
cell.propLabelCntReqs.text = item.propRequestCnt;
cell.propLabelCntDays.text = item.propDaysCnt;
NSLog(#"returning header cell %#",cell);
return cell;
}else if([item propCellType] == HomeOverviewItem_ITEM1){
CellHomeItem1 *cell = (CellHomeItem1 *)[tableView dequeueReusableCellWithIdentifier:#"cell_item1"];
cell.propLabelName.text = item.propName;
cell.propLabelCntReqs.text = item.propRequestCnt;
cell.propLabelCntDays.text = item.propDaysCnt;
NSLog(#"returning item1 cell %#",cell);
return cell;
}else{
CellHomeItem2 *cell = (CellHomeItem2 *)[tableView dequeueReusableCellWithIdentifier:#"cell_item2"];
cell.propLabelName.text = item.propName;
cell.propLabelCntReqs.text = item.propRequestCnt;
cell.propLabelCntDays.text = item.propDaysCnt;
NSLog(#"returning item2 cell %#",cell);
return cell;
}
}
EDIT:
I will add this image below to make sure that identifier is the same to what I am using on my code
Error:
Where could I possibly go wrong?
I bet your call to dequeueReusableCellWithIdentifier: is returning nil because initially there are no cells to be dequeued (from the docs: A UITableViewCell object with the associated identifier or nil if no such object exists in the reusable-cell queue.). Use
- dequeueReusableCellWithIdentifier:forIndexPath: as this will always return a valid cell.
I found the cause of my problem many thanks to the hint given by Bob....
I want to post this answers for future devs who might also experience this problem.
The one causing this problem is how I instantiate the viewcontroller.
for this case, NEVER instantiate the viewcontrollerv via alloc then init
instantiate the view using [storyboard instantiateViewControllerWithIdentifier:#"yourViewControllerID"]
i am using this method to return already created cells in storyboards
" dequeueReusableCellWithIdentifier "
and here is the code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
switch ( indexPath.row )
{
case 0:
CellIdentifier = #"map";
break;
case 1:
CellIdentifier = #"blue";
break;
case 2:
CellIdentifier = #"red";
break;
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier forIndexPath: indexPath];
return cell;
}
but i have this error :
'NSInternalInconsistencyException', reason: 'unable to dequeue a cell with identifier map - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'
note: i added the identifiers to storyboard as it is here and it dose not work, another important thing is that : this project was running but now it stopped !!!! I download it from appcoda.com
Here what Apple doc says:
Important: You must register a class or nib file using the registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier: method before calling this method.
…
Prior to dequeueing any cells, call this method or the registerNib:forCellReuseIdentifier: method to tell the table view how to create new cells. If a cell of the specified type is not currently in a reuse queue, the table view uses the provided information to create a new cell object automatically.
If you previously registered a class or nib file with the same reuse identifier, the class you specify in the cellClass parameter replaces the old entry. You may specify nil for cellClass if you want to unregister the class from the specified reuse identifier.
So you should register your class like this:
- (void) viewDidLoad {
[super viewDidLoad];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"map"];
}
I am creating the cell programatically using the reuse identifier.
Note - I am not using storyboard for creating the cell
Whenever the cell is dequeued, the cell is nil, so the cell needs to be newly created using alloc, which is expensive.
EDIT (added 1 more question and corrected code)
Question
Why does this dequeue always return nil ? How can I correct it ?
Does dequeue work only when used along with storyboard / nib file ?
Code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!cell) //Every time cell is nil, dequeue not working
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
return cell;
}
You need to first set the CellIdentifier as Cell. Are you doing that? When you are creating a new cell you need to assign this identifier Cell to it. only then iOS will be able to dequeueReusableCellWithIdentifier with that identifier. Programatically you can do it like so -
UITableViewCell *cell = [[UItableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"Cell"];
You can set identifier from Interface Builder too -
I was making a couple of mistakes:
I was using a subclass of UITableViewController, but was creating the tableView outside of the subclass
There is a tableView created in the table view controller, which is self.tableView In the tableview controller while returning the cell for index path, I was using self.tableView instead of tableView.
Also, ensure that the cell identifier is declared as static
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
Since tableView and self.tableView were representing different tables, the cell was not being dequeued from the same table and hence was always nil
This code should be generating the warning "control reaches end of non-void function" because you aren't actually returning anything. Add return cell; to the end of the function. Additionally, you never add the reuse identifier to the newly created cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
return cell;
}
First declare cell identifier for a tableViewCell at the viewDidLoad method as:
[tableView registerClass:UITableViewCell.class forCellReuseIdentifier:#"MyCell"];
Now recall the instance of the UITableViewCell with the same identifier "MyCell" as:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyCell" forIndexPath:indexPath];
Further just fill up the cell .. Now logic executes that limited number of cells are able to show enormously large list efficiently (using dequeue concept).
But remember to assign value (even nil if required) to every UIView used in the cell, otherwise overwriting / overlapping of text / images will happen.
I have a problem with my tableview. When I scroll and a cell disappears from the screen it becomes blank. I have built a prototype cell in the storyboard with two labels and one imageview, it have the same identifier that I use in my code. I also have built a custom class for the customcell. Here is the code in cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
Scientist *currentScientist = [[xmlParser data] objectAtIndex:indexPath.row];
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.self.cellName.text = currentScientist.self.name;
cell.self.cellSubject.text = currentScientist.self.subject;
cell.self.cellImage.image = currentScientist.self.image;
return cell;
}
I don't know if you need more code to help me.
In my case, creating a different cell identifier for each one worked just fine. I have something like:
NSString *cellIdentifier = [NSString stringWithFormat:#"identifier%i%i", indexPath.section, indexPath.row];
The rest should remain the same.
I found an article that details the problem you are encountering. I would also recommend printing out the Scientist data to ensure an object is being fetched correctly with the objectAtIndex:indexPath.row call.
From the article I linked below, I would be willing to bet that your dequeueReusableCellWithIdentifier is the problem. One quick way you could solve this is by giving each cell its' own unique cell identifier (Just to test out the theory). However, it looks the appropriate way to solve this is by changing up your cellForRowAtIndex method.
Source
I think many of us has faced this problem on UITableView delegate method - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath which gets called twice.
In my application I transforming the tableView. The code is:
CGAffineTransform transform = CGAffineTransformMakeRotation(-M_PI/2);
theTableView.transform = transform;
theTableView.rowHeight = self.bounds.size.width;
theTableView.frame = self.bounds;
Now inside the delegate method I am doing a couple of things:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
modelRef.currentCellAtIndexPathRow = indexPath.row;
static NSString *CellIdentifier = #"Cell";
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier frame:self.bounds] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
modelRef.currentPageIndex = (indexPath.row + 1);
[cell showPage];
NSLog(#" visible cell %i ",[[tableView visibleCells] count]);
return cell;
}
At a time 1 cell is visible, but first time when the application launches. The log shows visible cells 0.
Many a times this particular delegate method gets called twice abruptly.
How can I solve this?
I think an immediate fix is just to set a flag which changes the first time it is hit, so then you ignore the second call. It's probably not the perfect solution, and I can't tell you why it gets hit twice - but this will work. (I have experienced exactly the same behavior when I implemented an Apple delegate from the UIWebView class)
EDIT:
Create a BOOL member in the class header, then in the init set the value to be YES. So if the BOOL is called mbIsFirstCall for example, in your delegate method, do the following:
if (mbIsFirstCall)
{
// do your processing, then the line below
mbIsFirstCall = NO;
}
else
{
// you don't need this else, but just for clarity it is here.
// you should only end up inside here when this method is hit the second time, so we ignore it.
}