xcode / cocoa: Reuse identifiers in custom cells - objective-c

I have a tableview with custom cells via a uitableviewcell subclass. The cells have a label lblResult that changes after a a result is received. It works well, but, when I then scroll down my tableview, other random cells now have that same result label (but they still have their proper "name" label).
I figure this has to do with reuse identifiers, but I'm not sure.
Let me know if you need any more code to understand my problem.
The cell is made like this in cellForRowAtIndexPath
static NSString *CellIdentifier = #"tableCell";
FriendCell *cell =
[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[FriendCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:nil];
}
Then before being returned, cell is passed into a loadingQueue dictionary.
When the result loads there is a resultComplete method which loads the cell from the loadingQueue dictionary and the following is called:
[[cell lblNumTagged] setText:[NSString stringWithFormat:#"(%d)",[thisDictionary count]]];
[[cell lblNumTagged] setHidden:NO];

Yes it is because cells are being re-used.
In your custom cell class you can use the prepareForReuse delegate method, which is being called before the cell is being reused and clear the cell's label there...

I know this is old but just in case. I think it is because when you create a new cell you are NOT specifying the identifier.
static NSString *CellIdentifier = #"tableCell";
FriendCell *cell =
[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[FriendCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
Try it like this, note the end of the last line.....

Related

dequeueReusableCellWithIdentifier always returns nil (not using storyboard)

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.

Cells become empty after scrolling. (Xcode)

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

UITableViewDataSource method

Here is the CellForRowAtIndexPath method of UITableViewDataSource protocol. I saw that code on a website.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *TableIdentifier = #"SimpleTableItem";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:TableIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:TableIdentifier];
}
cell.textLabel.text = [playersReady objectAtIndex:indexPath.row];
return cell;
}
My questions are:
Why when here defined cell wrote = [tableView dequeueReusableCellWithIdentifier:TableIdentifier]; ? What that means? If I commented that code everything going OK. For what that code? Hmmm...
How cell in if statement can be equals to nil if cell equals to TableIdentifier (SimpleTableItem)? For what wrote that code?
Why TableIdentifier equals to SimpleTableItem? For What?
An iPhone doesn't have a lot of memory. But even on modern computers you wouldn't want to initialize a new cell for every cell in your table. That's just wasting memory. So instead Apple came up with this idea of reusable cells. You only have to initialize a few cells that fill your screen (table view). Then, when the user scrolls down some new cells will appear at the bottom of the screen, but at the same time other cells will disappear at the top of the screen. So you can simply take those cells and reuse them.
Luckily UITableView manages this for you. All you have to do when you need to setup a new cell in that method is ask the table view, if it has any cells available that can be reused. If there are reusable cells, dequeueReusableCellWithIdentifier: will return one of them. But if there are non available yet (typically when you first fill up your table view with the initial cells) it will return nil. So you have to test if cell is nil and create a new cell from scratch if that's the case.
On iOS 6.0 there is a new method dequeueReusableCellWithIdentifier:forIndexPath: that always returns a valid cell (it creates the cell for you if there is no reusable cell yet).
Table view Create only those cell which can Display at one time on screen.After this system reuse cell for save memory .
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 20;
}
-(UITableViewCell *)tableView:(UITableView *)tableViewL cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableViewL dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
NSLog(#"Cell == nil so create a new cell....");
}else {
NSLog(#"Reuse Cell ");
}
return cell;
}
CellIdentifier use for identify cell for example if you add label on first ten table on 12 cell you add a button it give you a problem when you reuse cell.so that we need create a different cell For add button on cell and give it a Identifier string.

Custom UITableViewCell Doesn't Draw Corectly

I'm having a really weird issue with my custom UITableViewCell. I have a cell with an identifier of "ThreadCell" in Interface Builder with some custom labels. These labels are tagged so I can access them.
In my code, I am doing the following:
static NSString *CellIdentifier = #"ThreadCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: #"ThreadCell"];
}
Person *person = [self.people objectAtIndex: indexPath.row];
UILabel *nameLabel = (UILabel *)[cell viewWithTag: 0];
nameLabel.text = person.nickname;
return cell;
This seems to work fine, with one exception. The TableView draws like this:
This obviously isn't my custom cell. But the weird thing is, when I tap on a cell, I get this:
This is my custom cell, drawn behind the default cell. What?! I'm not sure how this is happening because I do not ever set the title of the textview anywhere, so I'm not sure where the first John Smith comes from.
Anyone have any ideas?
In your code, you allocate a plain UITableViewCell and not an instance of your custom cell. Setting a reuseIdentifier in initWithStyle is not sufficient to load an instance of a custom cell class.
If you develop for iOS 5 and later, then you can use registerNib:forCellReuseIdentifier: to register a NIB file containing your custom cell. dequeueReusableCellWithIdentifier: will then always return an instance of that NIB.

Labels in Custom Cell do not appear

I am new to iphone development. I am using xCode 4.2 with storyboard. I am trying to get cells in my tableview to display several uilabels. They just aren't appearing in my simulator. but the original cell.textLabel is appearing.
here's what I did:
I created a new customcell.h/.m files that extend the UITableViewCell. I added some instance variables in the class. I went to the storyboard and in the class of the identity inspector of the tableviewcell, i changed it to point to customcell. I dragged and dropped some UIlabels into my new cell. I then went to the connection inspector to drag those "plus" icons with lines to connect to my new uilabels to my instance variables.
When I run my simulator, I don't see any of my new ui labels. I only see the original uilabel of cell.textLabel. I can programmatically get and set cell.mylabel1, cell.mylabel2 etc..., which are new labels, but hey just are not appearing.
Additioanl Details
This i the cellForRowAtIndexpath function for my tableviewcontroller.
static NSString *CellIdentifier = #"Cell"; // this was the error, i needed to change this to CustomCell, or whatever it is in my storyboard
CustomCell *cell = (CustomCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.mylabel1.text = #"hello"; // doesn't appear in simulator
cell.textLabel.text = #"world"; // does apepar in the simulator
As David has alluded, the one missing piece here is that you need to reference the Identifier of the cell specified in the Storyboard:
First, specify an identifier in the "Attributes Inspector" in the storyboard. You can do this by selecting the UITableViewCell and adding an identifier "ExampleCell" (for example). Second, reference this identifier in the code when creating the CustomCell.
static NSString *CellIdentifier = #"ExampleCell";
CustomCell *cell = (CustomCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}