Cells become empty after scrolling. (Xcode) - objective-c

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

Related

UITableViewController odd behavior

Sorry if this question look stupid but after hours of digging and searching with no success, I need to ask it here for you help.
I have a UITableViewController with 15 custom cell. Each cell has a UITextField inside.
here is the part of code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Static NSString *CellIdentifier = #"ADDFIELDCELL";
AddListContentCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[AddListContentCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
[cell.myTextField setTag:[self.tagsArray objectAtIndex:indexPath.row] integerValue]];
return cell;
}
The problem is when I type something in first cell (indexPath:0) after scroll down same text appear on 13th cell also. same mapping happens with 2nd and 14th cell.
I am really out of temper and do not what should I do. Any help will be appreciated.
The cell is being reused (hence the reuse identifier).
The textfield text for each cell needs to be linked to the datasource somehow (seems to be your tags array).
When you change the text on that cell, you have to modify the datasource text.
This way when the cell at index 2 rolls around, it will fill the textfield with whatever your tag item at index 2 of your datasource array has.

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.

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.

xcode / cocoa: Reuse identifiers in custom cells

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.....

Static UITableView created in IB/Storyboarding With dynamic content?

I'm wondering if I could make a basic UITableView and statically set up everything using IB/Storyboarding in Xcode 4.2 but just one of the cells I want to display the current app version. (I'm making an about view) and I don't want to hardcode the app version because I know I'll forget to update it down the road. Is there any way to have that one cell get its data from the dataSource? I tried implementing
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
if (indexPath.section == 0 & indexPath.row == 0) {
cell.textLabel.text = [self appVersion];
}
return cell;
}
I've tried setting the cellIdentifier on all cells to #"Cell" as well as just setting it on the cell I care about modifying.
and only for that cell returning the app version but that wipes out the content of all the other cells.
If you are using a Static table in Storyboards the static table is the data source.
With a Static Table in Storyboard you would put a UILabel in the cell in question. Than setup a IBOutlet property in your View Controller and hook up the label to the outlet.
Then just update the label to your version number. You can hook up as many outlets as you want to different cells in a static table. Static table just means there is a fixed number of cells , you can still dynamically change the content of those fixed number of cells.
Use different ID for the first row.