Let's say that I have
- (UITableViewCell*)tableView:(UITableView*) cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
static NSString *cellID = #"Cell Identifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
else
{
return cell;
}
UILabel * nameLabel = [[UILabel alloc] initWithFrame: CGRectMake( 0, 15, box.size.width, 19.0f)];
nameLabel.text = name;
[nameLabel setTextColor: [UIColor colorWithRed: 79.0f/255.0f green:79.0f/255.0f blue:79.0f/255.0f alpha:1.0f]];
[nameLabel setFont: [UIFont fontWithName: #"HelveticaNeue-Bold" size: 18.0f]];
[nameLabel setBackgroundColor: [UIColor clearColor]];
nameLabel.textAlignment = NSTextAlignmentCenter;
[cell addSubview: nameLabel];
}
What is that going to do?
If cell is not nil, and let's say you are at row 5, will it return the cell for row 5 with the exact text labels, etc?
Basically, my question is, if you have custom cells with labels, imageviews, etc. How do you use cellForRowAtIndexPath with dequeueReusableCellWithIdentifier?
You attempt to dequeue a cell. If the attempt failed (cell is nil), then you create a cell and configure it it's views (not the data inside the view). Afterwards, you populate the views with any data or settings that change cell-to-cell. Also, you should add any custom views to the cell's contentView, not the cell itself.
#define NAME_LABEL_TAG 1234
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID = #"Cell Identifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UILabel * nameLabel = [[UILabel alloc] initWithFrame: CGRectMake( 0, 15, box.size.width, 19.0f)];
nameLabel.tag = NAME_LABEL_TAG;
[nameLabel setTextColor: [UIColor colorWithRed: 79.0f/255.0f green:79.0f/255.0f blue:79.0f/255.0f alpha:1.0f]];
[nameLabel setFont: [UIFont fontWithName: #"HelveticaNeue-Bold" size: 18.0f]];
[nameLabel setBackgroundColor: [UIColor clearColor]];
nameLabel.textAlignment = NSTextAlignmentCenter;
[cell.contentView addSubview: nameLabel];
}
// Populate views with data and retrieve data for "name" variable
UILabel *nameLabel = (UILabel *)[cell.contentView viewWithTag:NAME_LABEL_TAG];
nameLabel.text = name;
// Return fully configured and populated cell
return cell;
}
If you have a complex cell, it's often easier to create it in Interface Builder and subclass UITableViewCell so you can have custom properties that refer to your Labels, Buttons, etc.
Yes, dequeueing a cell that you have already added those labels to will still have them and their text just as you left it when you created that particular cell.
Create a UITableViewCell subclass, let's call it MyTableViewCell that has properties holding the labels/imageViews/etc that it will need. Once you have either dequeued or alloc init'ed one of your MyTableViewCell, you can then set the text/images/etc on these properties. Like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"identifier";
MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[MyTableViewCell alloc] initWithStyle:UITableViewStylePlain reuseIdentifier:CellIdentifier];
}
cell.nameLabel.text = name;
cell.imageView.image = anImage;
return cell;
}
One major issue with your method is the conditionals surrounding dequeueing and creating. In your method you only set up the cell the label when it is alloc init'ed (you instantly return a dequeued cell without formatting it). However, you want this set up to occur for both dequeued and manually instantiated cells. Notice how this happens in my method, the return statement is at the very bottom. This will ensure that both created and reused cells have the appropriate data.
EDIT: One important thing I left out, you will instantiate the properties of your cell in its initWithStyle: reuseIdentifier: method and add them as subviews to the cell. This is so when you go to set the text of the label (or whatever) in your cellForRowAtIndexPath method, it has already been created. Basically the cell manages creating its own views and the UITableView delegate only has to worry about filling those views with data.
UITableView at first ask you for number of expected cells. Then it's load through - tableView:cellForRowAtIndexPath: method cells which is will be displayed + some to smooth scrolling, more objects it doesn't create. Created objects (by user) stored in table view and you can access not used through dequeueReusableCellWithIdentifier: method. TableView ask user for modifying currently created cells when it's scrolling. If here is free object - take it from dequeueReusableCellWithIdentifier: another - create new one.
in order to not have to allocate every single table cell, a table only allocates what is needed. If only 8 cells fit on a page then a table view will only allocate 8 cells or 9 i don't remember if it has a padding. When you scroll a tableview and the cell goes off the page the cell is queued up to be re-used, instead of re-allocating a new cell the table view takes an existing one this process is called dequeue-ing. When you make/allocate your cells you give it an identifier, this identifier is used to retrieve a cell that is marked with that string.
You can either use this
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath
This is available after iOS 6
Or you can also register your class somewhere in ViewDidLoad and use ResuseIdentifier, so you don't have to write the ResuseIdentifier part in CellForRowAtIndexpath
- (void)registerClass:(Class)cellClass forCellReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(6_0)
Hope this helps you...
Related
I am currently creating my cell like this
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
cell.imageView.image = [UIImage imageNamed:image];
cell.imageView.tintColor = [UIColor whiteColor];
cell.textLabel.text = #"Push me";
cell.textLabel.textColor = [UIColor whiteColor];
cell.userInteractionEnabled = YES;
return cell;
Everything is working fine but some of my text which is long gets truncated at the end. How can i avoid that?? I don't want to set the numberOfLines property.
Is there a way i can arrange my imageView and textlabel a bit via constraints so that my text looks fine. I tried adding constraints to contentView of cell but that make my cell all weird.
I am new to iOS development and learning. Any help will be greatly appreciated.
If you don't want to set numberOfLines. adjustsFontSizeToFitWidth property will set your content bound to width without truncating it. but it will decrease font size if required.
cell.textLabel.adjustsFontSizeToFitWidth = true
There is no need to add constraint programmatically,
Step 1 - Drag and drop the cell on UITableview
Step 2 - Design your cell with image view and label , use constraints
Step 3 - Create CustomCell.h and CustomCell.m file which will be inherited from UITableViewCell
Step 4 - create IBOutlet for image view and label in CustomCell.h
Step 5 - In your ViewController -
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CustomCell"];
cell.textLabel.text = [self.dataAraay objectAtIndex:indexPath.row];
return cell;
}
https://www.raywenderlich.com/129059/self-sizing-table-view-cells
UIImageView *imgarrow=[[UIImageView alloc]init ];
imgarrow.frame=CGRectMake(230,2, 27, 27);
imgarrow.image=[UIImage imageNamed:#"check_mark#2x.png"];
[cell addSubview:imgarrow];
//write same code for UILabel
//change rectmake values
I am using UITextField, and every row have a CellLable and TextField. Lable and TextField data comes from array. While running the app, all data are comes fine but when scrolling the Tableview, Last 2-3 Rows unorganized.
NSMutableArray
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
ArrFieldData= [NSMutableArray arrayWithObjects:#"Fist Name", #"Last Name",#"User Name", #"Password",#"Confirm Password", #"Gender",#"DOB", #"Profile Pic",#"Deparment", #"Joining Date",#"Education", #"Role", nil];
Now cellForRowAtIndexPath Function
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
UITextField *txtField ;
if (cell ==nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
txtField = [[UITextField alloc]initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/3 + 40, 2, [UIScreen mainScreen].bounds.size.width/2, cell.layer.frame.size.height -5)];
[self setUpCell:cell withIndexPath:indexPath withTextField:txtField];
}
[self UpdateCell:cell withIndexPath:indexPath withTextField:txtField];
return cell;
}
SetUp Cell Function
-(void)setUpCell:(UITableViewCell *)cell withIndexPath:(NSIndexPath *)indexPath withTextField: (UITextField *)txtField {
cell.textLabel.text = [ArrFieldData objectAtIndex:indexPath.row];
cell.textLabel.font = [UIFont systemFontOfSize:12.0];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
txtField.tag = indexPath.row+1;
txtField.layer.borderColor = [UIColor grayColor].CGColor;
txtField.delegate = self;
txtField.layer.borderWidth = 1.0f;
txtField.layer.cornerRadius = 4.0f;
txtField.placeholder = cell.textLabel.text;
txtField.font = [UIFont systemFontOfSize:12.0];
[cell.contentView addSubview: txtField];
}
Update Cell Function
-(void)UpdateCell:(UITableViewCell *)cell withIndexPath:(NSIndexPath *)indexPath withTextField: (UITextField *)txtField {
[self setUpCell:cell withIndexPath:indexPath withTextField:txtField];
}
First time Running the application, It is showing all cell and textfield data are Serialize. but when scroll some cell and TextField are not serialize as per Array Value. I am attaching the Simulator Screenshot.
First Screenshot for First time running, and second for when i scroll the Tableview. See the last 4-5 cell and Textfield Placeholder text. They are un-organized. I want it shouldn't change.
As you are using reusable cells, like
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
UITextField *txtField ;
if (cell ==nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
txtField = [[UITextField alloc]initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/3 + 40, 2, [UIScreen mainScreen].bounds.size.width/2, cell.layer.frame.size.height -5)];
[self setUpCell:cell withIndexPath:indexPath withTextField:txtField];
}
[self UpdateCell:cell withIndexPath:indexPath withTextField:txtField];
return cell;
}
UITableView uses the concept of reusable cell to achieve maximum performance by reducing the memory consumption, and to exploit this feature of reusing cells you can use the above UITableView's API's to achieve that.
But before using any feature it's very important to understand the working and the usage of any feature.
In your above implementation of tableView: cellForRowAtIndexPath: method, you have used the concept of cell reusability.
If the cells doesn't exist and are created for the first time, than they are allocated(every subview is created and added on the content view of the cell), customized and initialized with the data from the data source of the respective index path.
But in case the cells are reused(as they were already created for any other index path), there subviews exist with the data already filled for the previous index path for which it was created.
Now there are two things we can do to use already created cell for the current index path,
1) if the cells contain subview with data then remove the subviews and recreate the new ones, customize and populate them with the data.
2) rather than releasing the previous subviews and creating new ones, refill the data for the data model of the corresponding index path.
In your case, if the cell is being created for any index path, than the text filed for it is also created and if it's reused than the new text field is not created and it's being reused from the previously created cell thus the issue of the placeholder text not matching with the left text.
So, in order to solve your problem I think you should either create the textfield when the cell is created and if the cells are reused than refill the data in the text filed from the data source of the corresponding index path.
Your problem is due to a feature of UITableView. When you scroll a UITableView the indexPath is updated so you are not getting the index values you are expecting from the tableView.
Instead of adding a UITextField programmatically. Create a Custom UITableViewCell and from the method cellForRowAtIndexPath: update the placeHolder of your UITextField. The tableView will take care of scrolling for you.
Use this code :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
UITextField *txtField ;
if (cell ==nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
cell.textField.placeholder= cell.textLabel.text;
}
cell.textField.placeholder= cell.textLabel.text;
return cell;
}
I am expanding a UITableView cell on click.When the cell expands I have to load a UIView into it.My problen is that I am able to see the UIView on few occasions and sometimes it doesn't display ? The UIView is to be loaded in each and every expanded cell.
Expansion is done like this:-
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat kExpandedCellHeight =300;
CGFloat normalCellHeight = 94;
if ([self.expandedCells containsObject:indexPath]) {
return kExpandedCellHeight;
}else{
return normalCellHeight;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifier = #"Cell";
ListCell *cell =(ListCell*) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell==nil) {
NSArray *nibs = [[NSBundle mainBundle]loadNibNamed:#"ListCell" owner:self options:nil];
cell = nibs[0];
}
cell.Name.text = [[nameArray objectAtIndex:indexPath.row]valueForKey:#"opName"];
if (isExpanded) {
backgroundView = [[UIView alloc]initWithFrame:CGRectMake(0, 95, 320,205)];
[backgroundView setBackgroundColor:[UIColor colorWithRed:(235/255) green:(235/255) blue:(235/255) alpha:0.1]];
[cell.contentView addSubview:backgroundView];
container = [[UIView alloc]initWithFrame:CGRectMake(40, 67, 240, 120)];
container.backgroundColor = [UIColor whiteColor];
//I am adding buttons to this scrollview after webservice response,once buttons are loaded I am trying to load the above container on the background view.
container_scrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(20, 5, 220, 110)];
[container_scrollView setBackgroundColor:[UIColor whiteColor]];
[container addSubview:container_scrollView];
}
return cell;
}
Now I do get response from webservice.Buttons are added as well.However I can see the container view loaded sometimes and sometimes it doesn't show.What must be the reason?What is causing this behaviour?
This is how I load the container onto background view.
//After container is loaded with buttons.
if(backgroundView){
[backgroundView addsubView:container];
}
Declaration stuff:
#interface ListViewController ()
{
UIView *backgroundView;//Used in expanded cell.
UIView *container;
BOOL isExpanded; //I set this to NO in viewDidLoad initially.
UIScrollView *container_scrollView;
}
You should consider having two different cells on your storyboard or two xib files, each with its correspoding cellidentifier. One will be your normal cell and the other the expanded cell. Then whenever a user taps on one normal cell you should 'replace'(redraw) that specific cell with your second type cell (an expanded cell).
UPDATE
For performing the update of the cells you could use any of these methods. more here
reloadData
reloadRowsAtIndexPaths:withRowAnimation:
reloadSections:withRowAnimation:
Those will cause that some of your Table View Data Source delegate methods get called again, you should then use some logic to decide which kind of cell to draw. A quick draft:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier;
// Here you should implement your custom logic to check if you want a basic or expanded cell.
if (IWantBasicCell) {
cellIdentifier = #"basicCell";
} else {
cellIdentifier = #"expandedCell"
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
[cell myCustomLoadInformationMethod:myCustomData];
return cell;
}
I believe this question is my exact problem, but I was not able to fix the issue looking at the accepted answer.
UISearchBar: FilterContentForSearchText not working on a UITableView (results not shown on table)
I have a UITableViewController that allows searching. It was working perfectly via the default UITableViewCellStyle, then I decided to implement my own custom layout for the cells. I did not subclass UITableViewCell, but instead added two UILabels to the cell via Interface Builder and set up Auto Layout. I assigned them unique tags so that I can reference those labels in cellForRowAtIndexPath:. It works great - everything appears as expected, until you search. The search does work and it displays the sections and rows, but the labels on the rows have no text so the cell appears completely blank.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"List View Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
UILabel *leftLabel = (UILabel *)[cell viewWithTag:100];
UILabel *rightLabel = (UILabel *)[cell viewWithTag:101];
if (tableView == self.searchDisplayController.searchResultsTableView) {
leftLabel.text = ...;
rightLabel.text = ...;
}
else {
leftLabel.text = ...;
rightLabel.text = ...;
}
return cell;
}
I do know why the labels are blank. When you search, dequeueReusableCellWithIdentifier: returns nil so it inits a new cell with the reuse identifier, but that cell does not have a viewWithTag: and this results in left and right label becoming nil. So it obviously cannot add text to nil.
The answer provided in the link stated you should create the label in the if (!cell) statement and then call [cell.contentView addSubview:left{right}Label];. I did that, and then moved my label configuration code into that if statement as well. But when I do that, the main table's rows only has the default values of my left and right labels from Storyboard - it doesn't set the text of the labels. This is because dequeueReusableCellWithIdentifier: doesn't return nil and instead creates a new cell, so it doesn't ever set the text because that's in the if (!cell) statement.
I could not figure out how to take care of both situations: when cell is nil and when it is not. What do I need to do to fix this?
More comments: I've never used xib files before and I'd prefer to keep it that way. :) I wouldn't mind subclassing UITableViewCell if that's a solution. Of course, I would like to implement this the "proper" way - only create a cell when one is needed etc.
I think the easiest way to do this is to make your cell in a xib file if you want to use the same cell type for both the main table and the search results table. You can make a subclass if you want (you only need to put in IBOutlets to your two labels in the .h file), or do it the same way you already did using tags. In viewDidLoad of the table view controller, register the nib for both tables,
[self.searchDisplayController.searchResultsTableView registerNib:[UINib nibWithNibName:#"CommonCell" bundle:nil] forCellReuseIdentifier:#"CommonCell"];
[self.tableView registerNib:[UINib nibWithNibName:#"CommonCell" bundle:nil] forCellReuseIdentifier:#"CommonCell"];
Then in cellForRowAtIndexPath:, you only need to dequeue the cell with that same identifier, and populate the labels. There's no need to check for cell equals nil, because it never will be.
I modified one of my apps to show how you can implement cellForRowAtIndexPath. I subclassed the cell (CommonCell is the class), only adding IBOutlets to the leftLabel, and rightLabel,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
CommonCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CommonCell" forIndexPath:indexPath];
cell.leftLabel.text = ([tableView isEqual:self.tableView])? self.theData[indexPath.row] : self.filteredData[indexPath.row];
cell.rightLabel.text = ([tableView isEqual:self.tableView])? self.theData[indexPath.row] : self.filteredData[indexPath.row];
return cell;
}
This is conceptually wrong: you are instantiate a NEW CELL from code that is not the cell from interface builder. If you want use that on interface builder you need to register the nib for your tableView, and associate it to an identifier (se the same identifier also in the cell on interface builder):
[self.searchDisplayController.searchResultsTableView registerNib:[UINib nibWithNibName:#"NameNib" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:#"Identifier"];
But the question is: why? The best thing to do is create a subclass and add your labels. It is really simple:
1) Create a new file CustomSearchCell object that extends UITableViewCell:
CustomSearchCell.h
#import <UIKit/UIKit.h>
#interface CustomSearchCell : UITableViewCell
#property (strong, nonatomic) UILabel *leftLabel;
#property (strong, nonatomic) UILabel *rightLabel;
#end
CustomSearchCell.m
#import "CustomSearchCell.h"
#implementation CustomSearchCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
_leftLabel = [[UILabel alloc] initWithFrame:CGRectMake(100, 10, 200, 45)];
[_leftLabel setFont:[UIFont systemFontOfSize:20.0]];
[_leftLabel setTextColor:[UIColor blackColor]];
_rightLabel = [[UILabel alloc] initWithFrame:CGRectMake(100, 45, 200, 25)];
[_rightLabel setFont:[UIFont systemFontOfSize:15.0]];
[_rightLabel setTextColor:[UIColor grayColor]];
[self.contentView addSubview: _leftLabel];
[self.contentView addSubview: _rightLabel];
}
return self;
}
#end
2) In your view controller:
#import "CustomSearchCell.h"
and:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ListCellIdentifier";
CustomSearchCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[CustomSearchCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if (tableView == self.searchDisplayController.searchResultsTableView) {
cell.leftLabel = ...;
cell.rightLabel = ...;
}
else {
cell.leftLabel = ...;
cell.rightLabel = ...;
}
return cell;
}
I have added a UILabel as the content view of my tableview. The text in the UILabel is overlapping upon scrolling. Below is the code.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.chatTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Group"];
static NSString *CellIdentifier = #"Group";
UITableViewCell *cell = [self.chatTableView dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = self.latestTrimText;
UILabel *cellLabel = [[UILabel alloc]init];
cellLabel.text = self.dateOfLatestTrim;
cellLabel.frame = CGRectMake(15, 0, 150, 30);
[cell.contentView addSubview:cellLabel];
return cell;
}
I can fix this by changing to UITableViewCell *cell = [self.chatTableView dequeueReusableCellWithIdentifier:nil];
But then, the scrolling of the tableview won't be smooth. Is there another way to fix the issue?
The tableview cells are recycled and reused potentially an infinite amount of times. This is what the reuse identifier stands for.
Take care not to add any subview outside the if (cell==nil) block. Now you are just adding again and again a new label to the same cell instance. This is why your texts overlaps each other.
I would recommend you to read the documentation on how the cells are recycled and reused.
Your fix is not correct because by passing a nil reuse id, you are just preventing the recycling process to play. You create a new instance for each row of your tableview. This is why you have performance issues then.