Label value in custom tableview cell is changing while scrolling the tableview
static NSString *cellIdentifier = #"Cell";
cell = (CheckOutCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
// If there is no cell to reuse, create a new one
if(cell == nil)
{
cell = [[CheckOutCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.delegate = self;
CheckOutGroup * checkOut=_cartArray[indexPath.row];
cell.name.text=checkOut.name;
cell.size.text=checkOut.size;
cell.priceValue=checkOut.price ;
[array addObject:checkOut.dictionary];
[itemIdArray addObject:checkOut.itemId];
cell.price.text=[NSString stringWithFormat:#"Price:%#%#",self.currValue,checkOut.price];
cell.quantity.text=[NSString stringWithFormat:#"Qty:%d",1];
NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://sqwip.ignivainfotech.net/%#",checkOut.image]]];
cell.checkOutImage.image=[UIImage imageWithData:imgData];
NSUserDefaults *storeDefaults = [NSUserDefaults standardUserDefaults];
[storeDefaults setObject:self.currValue forKey:#"cur"];
cell.increaseBtn.tag=indexPath.row;
val=[checkOut.price intValue];
if (check==0) {
check=check+[checkOut.price intValue];
}
else
check=check+[checkOut.price intValue];
self.totalPrice.text=[NSString stringWithFormat:#"TotalPrice:%#%d",self.currValue,check];
return cell;
}
When a cell needs to be displayed (IE scrolling back onto the screen) the tableview controller is going to look at the data source and fire the some of its methods so it can display the correct information. In short its going to recall this method every time a cell needs to be displayed:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
If the cell is changing its because the data source is changing! I suggest placing a break point inside cellForRow and make sure the data from your:
CheckOutGroup * checkOut=_cartArray[indexPath.row];
or whatever is correct for the right cell before and after scrolling. If it is different and it shouldn't be, possibly you are grabbing the wrong data from the URL on the next pass or your indexes are getting out of place.
It's because of re-useability. Since UITableView reuse its cell on scrolling. To resolve this just make your cell nil.
Try this on CellForRowAtIndexPath:-
static NSString *cellIdentifier = #"Cell";
cell = (CheckOutCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(cell)
cell = nil
// If there is no cell to reuse, create a new one
if(cell == nil)
{
cell = [[CheckOutCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
Related
I was tasked to solve this bug in the app (It's for comercial use so I can't link the project). I'm also completely new to Objective-C or IOS development and I have no idea why the following happens. Reminder, I'm using custom cells.
When the tableview loads, everything looks fine.
Click here to see the example
But when I scroll up and back to the same postion the cell becomes blank, as if it had no data. Blank cell
If I repeat the same process everything looks fine again.
Here's the code for cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellId = #"cell2";
PedTableCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
if (cell == nil)
{
cell = [(PedTableCell*)[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
}
if (tableView==_table3)
{
NSString *docsDirr;
NSString *documentsDirectoryForSaveImages;
docsDirr = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
documentsDirectoryForSaveImages = [docsDirr stringByAppendingPathComponent:#"/CarpetaImatges"];
NSString *match = #".jpg";
NSString *preCodigo;
NSScanner *scanner = [NSScanner scannerWithString:[pedarray objectAtIndex:indexPath.row]];
[scanner scanUpToString:match intoString:&preCodigo];
NSString *nomimg=[NSString stringWithFormat:#"%#.jpg", preCodigo];
UIImage *img = [UIImage imageWithContentsOfFile:[documentsDirectoryForSaveImages stringByAppendingPathComponent:nomimg]];
cell.img.image = img;
cell.layer.borderWidth=1.0f;
cell.img.layer.borderWidth=1.0f;
cell.cart.text = preCodigo;
cell.descart.text = [nomarray objectAtIndex:indexPath.row];
cell.cant.text = [cantarray objectAtIndex:indexPath.row];
cell.precart.text = [precioarray objectAtIndex:indexPath.row];
cell.pvpcart.text = [pvparray objectAtIndex:indexPath.row];
[cell layoutIfNeeded];
}
return cell;
}
I've debugged the method and everytime it returns a valid cell. When I click the empty cell it still works as expected. Essentially, the data is there, it's just not rendered for some reason.
I've checked other posts with the same/similar issue but nothing seems to really match. PrepareForReuse is a no go since there's no UI to be changed, just content. I'm getting the values of the arrays with indexPath.row to make sure I'm fetching the correct value. I've even tried to set the heightForRowAtIndexPath to the same height the cell should have (all cells are of the same size and never change) or let AutoLayout handle it but to no avail.
Code of numberOfRowsInSection (Returns the amount of orders that exists in database currently):
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if(tableView == _table3)
{
[self cargacarro];
return pedarray.count;
}
return pedarray.count;
}
Any ideas?
Register your cell nib in storyboard or in code before tableview is loaded, and after replace dequeueReusableCell... with this one
PedTableCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId forIndexPath:indexPath];
cell.img...
cell.cart...
remove this part, is no longer needed
if (cell == nil)
{
cell = [(PedTableCell*)[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
}
I am little confused regarding the use of dequeueReusableCellWithIdentifier method and how it works. I currently have a searchBar and two mutable Arrays (say filteredTableData and tableData) . Now I just realized that no matter what I do cell always returns nil. I also have a filter feature on my UITableView (using different arrays) however it seems to always return a nil. My question is when does dequeueReusableCellWithIdentifier return something ?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableItem";
MMTableCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"MMTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
cell.RowNo = indexPath.row;
cell.ImageAlbum.image = [self getMP3Pic:indexPath.row];
cell.table = self.tableViewObject;
}
NSString* sng = isFiltered ? [self.filteredTableData objectAtIndex:indexPath.row] : [self.tableData objectAtIndex:indexPath.row] ;
cell.labelSongName.text = [NSString stringWithFormat:#"%#", sng ];
return cell;
}
This is actually an optimization of displaying UITableView. Imagine that you have 1,000 of data to display and it does not make any sense to create 1,000 UITableViewCell in order to host each of your data. So, we use something called reusability that only a certain amount of cells will be used. When scrolling, it's not actually dealloc the invisible cells and create new cells. It's just move the existing cells around.
The identifiers are just used to identify different cells based on what you need. I might have multiple cell prototypes being used in one UITableView.
For your question, you will need to set up prototyped cells in the Interface builder. In the programmatical way, if we can not find the cell using dequeueReusableCellWithIdentifier method, then we create. But, you can take advantage of Interface Builder and it will always return cell.
dequeueReusableCellWithIdentifier is nothing but reusing the Cell whenever applicable. Initially cell is always nil. So, we check for cell==nil condition and we will create UITableViewCell first time. When u scroll the tableview then dequeueReusableCellWithIdentifier will be called to reuse the cell which is already created at First Time.
You can modify your code as below
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableItem";
MMTableCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[MMTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier] ;
}
cell.RowNo = indexPath.row;
cell.ImageAlbum.image = [self getMP3Pic:indexPath.row];
cell.table = self.tableViewObject;
NSString* sng = isFiltered ? [self.filteredTableData objectAtIndex:indexPath.row] : [self.tableData objectAtIndex:indexPath.row] ;
cell.labelSongName.text = [NSString stringWithFormat:#"%#", sng ];
return cell;
}
Try it..Hope it helps you..!
I want to create more detailed table cells. An example I found is the reddit.com client AlienBlue. Each cell has an image, the title of the post, then below it four other pieces of text. How can I "layer" text in a table cell?
Hi you should subclass UITableViewCell for custom User interface of a cell in a table view.
Also look at: UITableViewDataSource and UITableViewDelegate for other options with regard to table view.
Probably your subclassed UiTableViewCell will have custom fields for title (UILabel), caption (UILabel) and for an image (UIImageView)
Examples:
Crafting Custom UITableView Cells
Customize Table View Cells For UITableView
You will want to create a custom UITableViewCell. It's quite trivial, and can be done either entirely in code (my favorite) or through IB.
Google custom UITableView cell for some great tutorials.
Use NSMutableArray of NSMUtableDictionary, as opposed to NSArray or NSMutableArray, to hold data (strings, images, ...).
Set the table cell style property to UITableViewCellStyleSubtitle so that the table can display the detailedTextLabel (cell.detailTextLabel.text).
You can set an image to the table cell.
Example
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
// Configure the cell...
UIImage *image = [[list1 objectAtIndex:indexPath.row] objectForKey:key1a];
cell.imageView.image = image;
NSString *categoryname = [[list1 objectAtIndex:indexPath.row] objectForKey:key1b];
cell.textLabel.text = categoryname;
cell.detailTextLabel.text = [[list1 objectAtIndex:indexPath.row] objectForKey:key1e];
cell.detailTextLabel.textColor = [UIColor blueColor];
return cell;
}
- (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];
}
cell.textLabel.text=[NSString stringWithFormat:#"%#",[appdelegate.name objectAtIndex:indexPath.row]];
UIImage *image = [[array1 objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [[array1 objectAtIndex:indexPath.row];
return cell;
}
I got a prototype table with a custom Cell and inside this cell a textField.
My array of cells is a large one, so when I scroll the table, the cells need to be recreated.
Testing, when I scroll the text that was in the txt field of 1 cell goes to another, keyboard types change and everything gets messed-up!
CODE:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"customTableCell";
customTableViewCell *cell = (customTableViewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[customTableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:nil];
}
// Configuration
cell.lblName.text = [self.pfFields objectAtIndex: [indexPath row]];
cell.txtType = [self.pfTypes objectAtIndex: [indexPath row]];
cell.mySql = [self.pfSql objectAtIndex: [indexPath row]];
//cell.txtField.delegate = self;
if ([[self.pfTypes objectAtIndex:[indexPath row]] isEqualToString: #"n"]) {
[cell.txtField setKeyboardType:UIKeyboardTypeNumberPad];
} else if ([[self.pfTypes objectAtIndex:[indexPath row]] isEqualToString: #"m"]) {
[cell.txtField setKeyboardType:UIKeyboardTypeEmailAddress];
}
return cell;
}
You need to be sure to set all properties of a cell in tableView:cellForRowAtIndexPath:, because a given cell can be reused at any time by the controller.
To prevent the text from jumping around, you need to set cell.txtField.text to the appropriate NSString loaded from your cell's backing object. Similarly, you should always set the keyboardType every time (I assume that there are cases besides just n and m). Setting the properties every time ensures that you get the correct display regardless of how the reused cell was previously configured.
I've checked a few other questions but still can't figure out why this is happening. All I know is after using the description code from this question the cell's value is null. I've set the delegate and datasource of the table correctly and I can't see where this is going wrong.
If I set the return value of the following method to 0, no error occurs because the cellForRowAtIndexPath method doesn't really take place. So if I set it as 1 (as it should be) it'll then throw the error. I've synthesized the NSArray and checked that its populated (although that shouldn't matter I guess) and basically what is meant to happen is I press a button that searches and then places the results in the table. So before this the tableview is empty.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
Here's the cellForRowAtIndexPath method itself. I've tried just using the basic template method too, which still throws the same error.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
NSDictionary *aResult = [results objectAtIndex:[indexPath row]];
NSLog(#"RESULTS IN TABLE %i", [results count ]);
id key = [results objectAtIndex:[indexPath row]];
resultTitle.text=#"Hello";
NSURL *url = [NSURL URLWithString:[aResult objectForKey:#"url"]];
NSData *data = [NSData dataWithContentsOfURL:url];
cell.imageView.image = [UIImage imageWithData:data];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
[theTableView reloadData];
return cell;
}
I've no idea what is wrong. I've used tableviews before and have compared this project to others to see if I've missed something, but I can't see any real differences.
you are not initisialing the cell if nil is returned from the dequeue method
change
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
to
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
You do not have a method to return the number of rows in section 0 - this is a required data source method (in this case).