Custom UITableViewCell is nil - ios

I am using xib to load the cell in the UITableViewController. There is a button on the cell by hitting which a modal pops up and when we hit something on that modal, I want to change the image in the cell. But I am not able to get the cell even if I am passing the indexPath.
I have used following code:
NSIndexPath* indexPath1 = [NSIndexPath indexPathForRow:sender inSection:0];
[self.tableView2 reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath1, nil] withRowAnimation:UITableViewRowAnimationNone];
I have written the code in the cellForRowAtIndexPath as follows:
if([[feedbackDictionary objectForKey:[NSString stringWithFormat:#"Key%li",indexPath.row]] isEqualToString:[NSString stringWithFormat:#"%li",indexPath.row]])
{
NSLog(#"Yay! Feedback");
cell.checkmark.image=[UIImage imageNamed:#"tick"];
}
else
{
NSLog(#"Oops! No feedback");
cell.checkmark.image=[UIImage imageNamed:#"orangetick"];
}
I am supposing that when reloadrows will run,it will reload that particular cell by calling cellForRowAtIndexPath. But it is of no help. The image is not changing at all.
Secondly, I tried to get the cell by using following
NSIndexPath *ip=[NSIndexPath indexPathForItem:button.tag inSection:0];
ExpandingCell *cell=(ExpandingCell*) [_tableView2 cellForRowAtIndexPath:ip];
if(cell==nil)
{
NSLog(#"No cell");
}
I am getting no cell as output. Please help.

At first, to debug it try to call [self.tableView2 reloadData]. If your image is changed, it means that you were called wrong indexPath for reloadRowsAtIndexPaths method.
Also button.tag could return wrong tag, because cells are reusable in UITableView, and it can be cell that already used before.

I have found the problem and fixed it. The problem was when modal pops up,it was loosing control over the view controller and that is why tableview is null and nothing was changed.

Related

UITableViewCell selection flickers on reload

I have a UITableView which I have hooked up to a NSFetchedResultsController. When an object is updated, I use reloadRowsAtIndexPaths to reload the cell. I want to keep the cell selected while it is reloaded. The below code is how I am reselecting the cell after the update. It works, but the cell displays unselected for about half a second before becoming selected again and looks bad. self.selectedIndexPath is set in didSelectRowAtIndexPath.
I've also tried setting the cell to selected and highlighted in cellForRowAtIndexPath, but that did nothing.
Does anyone know how to prevent the flickering? I'm using iOS 8.3 BTW.
// Called in controllerWillChangeContent
[self.tableView beginUpdates];
...
// Called in didChangeObject
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
...
// Called in controllerDidChangeContent
[self.tableView endUpdates];
if( self.selectedIndexPath ) {
[self.tableView selectRowAtIndexPath:self.selectedIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}

Validity of the UITableView Cells in ViewWill Appear

What I have
1). Container has UITableView, which has two custom UITableViewCells.
2). Core Data has certain entity which has a text to be displayed at
UITableViewCell each time I get into the View.
What i am doing ?
1) I have chosen -viewWillAppear method which gets invoked each time the view is visible.
2) In -viewWillAppear, I retrieved the data from core data.
3) Retrieved particular cell from UITableView
NSUInteger idxArr[] ={2,0}; // 2 nd section, 0th Row.
NSIndexPath *cPath = [NSIndexPath indexPathWithIndexes:idxArr length:2];
myCell *tCell = (myCell *)[self.settings cellForRowAtIndexPath:cPath];
tCell.myLabel.text = rec.servername; // rec.servername is from DC.
When I checked in the lldb,
tCell was nil.
Questions:
1) It is the right way of getting the Cell ?
2) Or, By the time -viewWillAppear, does the UITableView not Ready ?
I am sure.
You should populate the cells by conforming to tableView dataSource protocol and then in your viewWillAppear you should call reloadData on your tableView.
After calling reloadData for tableview, We need to call -scrollToRowAtIndexPath: before getting cell from -cellForRowAtIndexPath:.
Because, As we are calling a row in section 2, it might not be in the visible area until we scroll. So, cellForRowAtIndexPath: returns nil.
Method -cellForRowAtIndexPath: shouldn't be called programically. It's a data source method for UITableView and it contain some cell reuse optimalizations. If you update the view after scrolling down and up -tableView:cellForRowAtIndexPath will be called again and your changes won't be visible.
If you want to update specific cell you should update make changes in:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
YourCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CellId" forIndexPath:indexPath];
YourData *data = //Get your data here
if (data.isReady) {
cell.tf.text = data[indexPath.row].text;
} else {
cell.tf.text = #"Not ready yet. Need to reload this cell later";
}
return cell;
}
And then call method below when you finish fetch your data.
[self.tableView reloadRowsAtIndexPaths:(NSArray *) withRowAnimation:UITableViewRowAnimationFade];
If you want to reload whole tableView (usually it's not slow) as #salaman140 says you can call [self.tableView reloadData] to update all visible cells.
If I were you I wouldn't use:
NSUInteger idxArr[] ={2,0}; // 2 nd section, 0th Row.
NSIndexPath *cPath = [NSIndexPath indexPathWithIndexes:idxArr length:2];
I would (is much more clear):
NSIndexPath *cPath = [NSIndexPath indexPathForRow:0 inSection:2];

Update Specific cells in a tableView without calling reloadData

I have an app in which I have a UITableview with custom cells and headers. The cells have an inputView so when selected they become first responder and allow the user to input data.
I want to be able to update the visible TableViewCell and header information on the fly while the user is changing it.. easy, just call [tableview reloadData]; ..
Unfortunately this causes the inputview to resign first responder and hide itself.
Is there any way that I can get a reference to the cell itself inside the UITableview so that I can just change the text property? (cellForRow:atIndexPath: returns a new object with the same properties so doesn't work) It seems like the only easy solution may be to store a reference the cells in a dictionary each time a cell is populated, not really the ideal solution.
cellForRowAtIndexPath is literally just
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *orderCell;
static NSString *productCellIdentifier = #"ImageDetailCellIdentifier";
orderCell = [self.tableView dequeueReusableCellWithIdentifier:productCellIdentifier forIndexPath:indexPath];
//set a bunch of properties orderCell.blah
return orderCell;
}
According to UITableView documentation, -cellForRowAtIndexPath: returns an object representing a cell of the table or nil if the cell is not visible or indexPath is out of range.
That is also how I remember it. I don't think your observation is correct that it returns a new object. If the cell is visible you will get hold of it.
[tableView beginUpdates];
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade]; ///as your choice in animation
[tableView endUpdates];
or else
[tableView beginUpdates];
// do some work what ever u need
[tableView endUpdates];
For reloading specific rows, you can use
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
For example,
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:2 inSection:1];
NSArray* indexArray = [NSArray arrayWithObject:indexPath];
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];

tableviewcontroller within container view controller: programatically selecting uitableviewcell, highlighting blinks

I am trying to programatically highlight a table view cell and trigger the selection logic by doing the following
NSIndexPath*indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
[self tableView:self.tableView didSelectRowAtIndexPath:indexPath];
The row highlights only for a split second. I want it to stay highlighted until I select another row.
I tried adding these lines
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath: indexPath];
cell.highlighted = YES;
but when I did this, the highlight remained even when I clicked on another row and did not go away until I clicked the first row again.
Any ideas?
Try calling selectRowAtIndexPath but not didSelectRowAtIndexPath. I believe the latter is called as a result of the former. If your delegate deSelects the last selected index path in didSelectRowAtIndexPath, then the double call would result in deselecting what you had just selected
seems like the issue was because I was calling the code from viewDidLoad, I moved it to viewDidAppear and now its fine

Force UITableView to call cellForRowAtIndexPath: for all cells

I am having some trouble with UITableView's reloadData method. I have found that it only calls cellForRowAtIndexPath if there are new cells being added or taken away.
Example: I have five cells, each containing five strings. If I add a new cell and call reloadData, the table is updated and I see it. Yet if I go into one of the five cells, add a new string, then return and call reloadData, none of the table view's delegate methods is called.
My question: Is it possible to force the table view to completely reload the data in all of its visible cells?
I found the problem- I had my cell customization code in the if(cell == nil) block, so because the cells were being recycled, they weren't being changed. Taking my customization code out of that block fixed the problem.
I've found that reloading sections reloads data more readily. If you just have one section you can try:
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone];
You can try this
[tableView reloadData];
or
[tableView deleteRowsAtIndexPaths:[NSMutableArray arrayWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationFade];
put this in commitEditingStyle method.
Well, the table view's only going to call cellForRowAtIndexPath on the visible cells but if you do call reloadData it will do that so there's something else going on here and I'm not sure what it is.
Even if your tableview has 50 rows, there only will exist as much cells as can be visible at one time. That's the whole story behind the reuseIdentifier. So forcing 'all the cells' doesn't exist. If a new cell appears, the data is loaded dynamically.
The only way to change a cell is to change the data that is delivered by the dataSource method cellForRowAtIndexPath.
Do not take your code out of the if (cell == nil) block. Instead, create a representative identifier for the cell you're making; try and make sure that all of the cell's content is referred to in the identifier. For example, if you have 3 numbers showing, make sure to have those three numbers in the identifier in a unique way that would only refer to a cell that has such content.
Let's say you have three NSArray properties in your class, array1, array2, and array3 that have int values wrapped inside of NSNumber objects. You want to use those NSArrays to fill a UITableView, this is what I'd do:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *identifier = [NSString stringWithFormat:#"%#-%#-%#",
[[array1 objectAtIndex:indexPath.row] intValue],
[[array2 objectAtIndex:indexPath.row] intValue],
[[array3 objectAtIndex:indexPath.row] intValue]];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:identifier] autorelease];
//Build your cell here.
}
return cell;
}

Resources