I want to change the state of a cell in a TableView. I tried setting the state in "cellForRowAtIndexPath" method, but it did not work. Then I saw posts that said that in order to change the state of a cell one needs to use the delegate method "willDisplayCell". However, when I implemented the method it is not being called (I put a breakpoint which was not called)
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
cell.selected = true
}
I tried also using "willDisplay" as it appears in Apple documentation, but that did not help. As a matter of fact, I tried any garbage instead of that string and nothing happens - the app compiles with no errors but the method is not being called.
I know that the delegate of the tableView is working because other delegate methods, such as "didSelectRowAtIndexPath", are being called.
Swift 3.0 syntax for willDisplayCell is now:
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
}
Related
I've been working around the tableview and got stuck on the following issue.
As far as I understand, the willDisplayCell delegate method should allow me to access the current cell design.
My issue is: it does not work properly. That delegate function runs only five times when trying to display 80 cells. Regardless of anything other than this function, writing a line of code in the delegate function makes it work well.
Here is my code:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if indexPath.row == comment_arr.count - 1 {
print("end")
// (1)self.comment_height.constant = self.comment_table.contentSize.height + 30
}
// (2)self.comment_height.constant = self.comment_table.contentSize.height + 30
}
If the (1) line exists, it doesn't work. But if the (2) line exists, it works well.
How do I get it to work?
First get the number of rows in section. Then find the last item
let totalRow = tableView.numberOfRows(inSection: indexPath.section)
if(indexPath.row == totalRow - 1)
{
print("end")
return
}
tableView(_ tableView: UITableView,
heightForRowAt indexPath: IndexPath) -> CGFloat
is called before willDisplayCell
the topic was covered in full and detailed way here:
TableView methods
I am having an issue using a UITableView's didEndDisplayingCell method. I am using this method along with willDisplayCell to handle some extra data tracking for my table. The problem is that didEndDisplayingCell is being called several times in a row, and at times where the cell is actually still being displayed. I cannot figure out why this would happen.
More Details
I am using an NSFetchedResultsController to provide data for the table. Changes come into the table from an NSManagedObjectContext on a different queue and then get merged into the NSManagedObjectContext that the table uses. This all seems to be working fine. Looking at my implementation of the above methods:
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
debugPrint("willDisplay cell at \(indexPath).")
self.dataProvider.addTrackedRelatedRecords(for: indexPath)
}
override func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
debugPrint("didEndDisplaying cell at \(indexPath).")
self.dataProvider.removeTrackedRelatedRecords(for: indexPath)
}
The output I'm seeing here is:
"Updating rows in table at [0, 0]". <=== This is an update to the data
"willDisplay cell at [0, 0]." <=== This is what I expect
"didEndDisplaying cell at [0, 0]"
"didEndDisplaying cell at [0, 0]"
"didEndDisplaying cell at [0, 0]"
The cell remains visible in the table and never disappears. There is nothing that I can see that would cause the didEndDisplaying to be called, especially repeatedly.
I can work around this issue by checking to see if the cell is actually still visible, by adding the following to the didEndDisplayingCell method:
override func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
debugPrint("didEndDisplaying cell at \(indexPath).")
// WORK AROUND
if let visibleRows = tableView.indexPathsForVisibleRows, visibleRows.contains(indexPath) {
return
}
self.dataProvider.removeTrackedRelatedRecords(for: indexPath)
}
This correctly sees that the cell is still visible, so won't remove my extra tracking. But, if the cell is visible, why is the method being called at all?
Obviously there is a lot of other code at work in my app. I will attempt to cull this down to a very simple case, but thought I'd post this first to see if anyone has seen cases where this might happen. That might help me track it down.
Thanks for any insight.
I found the issue and I'm posting an answer in case anyone else sees this issue and would be helped by what I found.
It turns out that I had inadvertently left a tableView.reloadRows(at: [indexPath], with: .fade) inside a tableView.beginUpdates() and tableView.endUpdates() block.
I believe that the reloadRows was causing the cell to be replaced, which would cause a didEndDisplayingCell. And, since there were a couple updates happening inside the block, these were being queued up and posted once the tableView.endUpdates() was called.
Removing the reloadRows call fixed the issue and all is working as expected.
In my case it was because I was calling reloadData() whenever I was changing the centeredIndexPath. Make sure you are not reloading the data as all the cells will call didEndDisplaying (as you are reloading it).
The UITableViewDelegate has a convenient function, willDisplay.
I need to add a handler for when a cell hides, which is essentially the opposite of willDisplay. How can I detect this event?
The method you'll want to use is
func tableView(_ tableView: UITableView,
didEndDisplaying cell: UITableViewCell,
forRowAt indexPath: IndexPath)
Documentation
I get this error message: failed to obtain a cell from its dataSource
The strange that
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
not even get called, problem is not that returned cell is nil. I put in breakpoints. cellForRowAtnot get called.
numberOfRowsInSection returns value.
I do not know it is relating or not, but now I do not use UITableViewController, I just have a UIViewController, and it is the datasource and delegate for the UITableView. I hope it can not cause interfere. Any idea?
Cross check below check list:-
it's because you are failing to dequeue a reusable cell.
The problem is that your cellForRowAtIndexPath function is embedded in another function
when you forgot to add the UITableViewDataSource and UITableViewDelegate protocols to the ViewController declaration.
class DataViewController: UIViewController, UITableViewDataSource, UITableViewDelegate
I guess this is your problem - Failed to obtain a cell from its DataSource
you can take a look at: https://www.hackingwithswift.com/example-code/uikit/fixing-failed-to-obtain-a-cell-from-its-datasource
try something like this:
cell = tableView.dequeueReusableCellWithIdentifier(getCellIdentifierForType(cellType))
setDataToCell(cell, item: item)
good luck
Please make sure when you are migrating your code from swift older to new versions then your tableview data source and delegates have updated syntax.
For example
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
and
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
Can not auto updated to below:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
I'm in the midst of transitioning some of my code from ObjC to Swift. So far so good, but I'm running into an issue with some of my UITableView's delegate methods not being called. In ObjC, I had my cells animate into the view using the tableView willDisplayCell forRowAtIndexPath method. While the method is suggested to me in Swift, it is never called. The same goes for tableView willDisplayHeaderView forSection, and tableView editActionsForRowAtIndexPath.
I'm fairly sure my class is set properly:
class MyViewController: UIViewController, UITableViewDelegate, UITableViewDataSource
and my function declarations were suggested, so no way these are incorrect.
func tableView(tableView: UITableView!, editActionsForRowAtIndexPath indexPath: NSIndexPath!) -> [AnyObject]! {
...
}
func tableView(tableView: UITableView!, willDisplayCell cell: UITableViewCell!, forRowAtIndexPath indexPath: NSIndexPath!) {
...
}
etc.
But while the tableView data shows up great, these individual delegate methods never seem to run. Is this a bug, or am I missing something? Thanks!
Did you tell to your table view about delegate and data source?
self.tableView.delegate = self;
self.tableView.datasource = self;