Custom cells in UITableView become blank after scrolling up or down - ios

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];
}

Related

Understanding dequeueReusableCellWithIdentifier

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

label value in custom tableview cell is changing while scrolling

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];
}

iOS 7 UITableViewCell issue

I have an iOS 6 app that I am converting to iOS 7 using Xcode 5 in StoryBoard. Everything worked fine until I decided I wanted to add a custom UITableViewCell to a tableview controller after converting the app to iOS 7. I created the usual code to do this but when I run the app it gives an unexpected result whereby it just displays the contents of one cell row and it sort of floats above the tableview which shows what appears to be empty cell rows behind it. When I scroll the table rows, I see them scrolling in the background and the data being shown in the one view cell row changes while scrolling (see image attached). However, if I click on what looks like an empty row, it works correctly and it segues correctly to the detail view controller. I made the same changes to the app in iOS 6 using Xcode 4.6 on my other macbook and it works correctly (see image attached). So I'm thinking that iOS 7 handles the uitableviewcell class differently than in iOS 6 or I am making a mistake in the code in the iOS 7 app and not realizing it.
Here is the iOS 7 code that's not working correctly:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Cell";
ExhibitorsViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[ExhibitorsViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
if (tableView == self.myTableView){
NSManagedObject *object = [self.objects objectAtIndex:indexPath.row];
cell.nameLabel.text = [object valueForKey:#"name"];
NSString * booth = [NSString stringWithFormat:#"Booth Number: %#", [object valueForKey:#"boothLabel"]];
cell.boothNumberLabel.text = booth;
}
else{
NSManagedObject *object = [results objectAtIndex:indexPath.row];
cell.nameLabel.text = [object valueForKey:#"name"];
NSString * booth = [NSString stringWithFormat:#"Booth Number: %#", [object valueForKey:#"boothLabel"]];
cell.boothNumberLabel.text = booth;
}
return cell;
}
Here is the iOS 6 code that works (to me it seems to be the same, but I guess I need other eyes to view it):
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"Cell";
ExhibitorsViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (!cell) {
cell = [[ExhibitorsViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
if (tableView == self.myTableView){
NSManagedObject *object = [self.objects objectAtIndex:indexPath.row];
cell.nameLabel.text = [object valueForKey:#"name"];
NSString * booth = [NSString stringWithFormat:#"Booth Number: %#", [object valueForKey:#"boothLabel"]];
cell.boothNumberLabel.text = booth;
}
else{
NSManagedObject *object = [results objectAtIndex:indexPath.row];
cell.nameLabel.text = [object valueForKey:#"name"];
NSString * booth = [NSString stringWithFormat:#"Booth Number: %#", [object valueForKey:#"boothLabel"]];
cell.boothNumberLabel.text = booth;
}
return cell;
}
Here is the screen shot of what's happening in the iOS 7 app.
Here is what it should look like (this is before I made the custom UITableViewCell changes).
I figured it out. I had to drag the uilabel a little above the uitableviewcell until I see the cell boundaries highlighted. This placed the label above the cell. I then had to move the label back into the viewcell. Never had to do that in xcode 4.6. But, oh well.

xcode tableview messing textfield data

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.

iOS: UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:

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

Resources