Swift (some) UITableViewDelegate Methods Not Executing - ios

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;

Related

Why does Xcode auto-fix create two methods with the same name `func tableView`?

I am new to swift programming language. I've seen that in creating table in Swift, you have to implement two methods in ViewController class that extends UITableViewDelegate, UITableViewDataSource. What I don't understand is, why does Xcode's auto-fix create two methods with the same name func tableView in this class?
Is this not going to create method overloading or cause bug down the road?
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tableView: UITableView!
let dataArray = ["firt", "second", "third", "four", "five", "six"]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let videoCell = tableView.dequeueReusableCell(withIdentifier: "video title", for: indexPath)
return videoCell
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
tableView.dataSource = self
tableView.dataSource = self
}
}
Even though they have the same function name tableView
They are very different functions.
They both conform to the UITableView delegate and based on its protocol method will affect different functionalities of the tableView.
didSelectRowAt
is not the same as
cellForRowAt
Did Select row at is only triggered when you obviously select a cell
Cell for row at is considered the 'main' tableView function, as this function populates your tableView data cells.
--EDIT
Based on Duncan C comment below.
" the name of your example function is not tableView, The name of of the function is tableView(_:cellForRowAt:) (The parameters are actually part of the function's name, or rather it's function "signature.") "
This is an excellent way to describe the answer.
Edit 2----
Furthermore,
This is very common among programming in swift. The most direct example would be collectionView. It uses almost the identical naming convention.
cellForRowAt
and
didSelectRowAt
There are many other delegate methods that you will encounter with the same situation as you describe in your question.
They are actually different methods. Each one overrides some properties of your TableView.
Just pay attention to the parameters of each function.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
This method creates and configures an appropriate cell for the given index path.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
Here you decide what happens when cell rows are clicked (go to another view, display some content, etc)
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
Returns the number of rows each section of your TableView should have.
And so on. There are many others methods that you can use for different reasons. To see which methods you can override, type tableView on your Xcode and see the autocomplete options.
That is called method overloading. Swift designers chose to follow this way of writing functions to make it easier for the programmers to find all related tableView functions. That tableView has many more functions like:
a one that has heightForRowAt and willDisplayCell in its parameters. Swift utilizes heavily a pattern called Delegate Pattern, the framework calls these tableView functions when you assign your ViewController as a delegate.

willDisplayCell of UTTableView is not called

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) {
}

UITableview: failed to obtain a cell from its dataSource

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

Swift - table view delegate methods not getting called from view controller class

I have a UITableView placed on a view controller in storyboard. I set the datasource and delegate for the table view to self and I specified the UITableViewDelegate and UITableViewDatasource in the view controller class declaration. All of the datasource functions work properly. In other words, when cellForRowAtIndexPath is called, it executes fine.
The problem is that the delegate methods for the tableView are not executing. I verified this by placing a breakpoint at the beginning of
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
I also noticed that the keyword optional is specified to be prefixed for the above delegate method as such:
optional func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
However, if I add the optional keyword to the beginning of the function, I get the error optional can only be applied to protocol members.
I have no idea why my heightForRowAtIndexPath is not getting called. Can anyone help me on this? Thanks in advance.

Type 'ProfilesTableViewController' does not conform to protocol 'UITableViewDataSource' in Xcode 6 GM seed

Today I migrated to Xcode 6 GM seed and now I get the following error:
Type 'ProfilesTableViewController' does not conform to protocol
'UITableViewDataSource'.
I've overrided numberOfRowsInSection, cellForRowAtIndexPath and numberOfSectionsInTableView. In fact everything worked fine till today. I noticed that when I remove UITableViewDataSource everything is working fine, and no errors occured. So .. Is it necessary to use 'UITableViewDataSource' anymore, or just override the functions from it?
This code compiles fine:
class ProfileTableViewController: UITableViewController, UITableViewDelegate, UITableViewDataSource {
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("foo", forIndexPath: indexPath) as UITableViewCell
return cell
}
}
So, you can definitely subclass UITableViewController and define its UITableViewDataSource protocol implementation.
Take notice that I am using the override keyword and also that I am not using auto-unwrapped arguments -- i.e., not like this:
override func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
which was correct in previous Xcode 6 betas.
My guess is that you're not implementing all the required methods, based on the error, at least.
EDIT: Because of the Xcode 6 beta syntax:
override func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!){
We had to check the unwrapped tableView. So I used:
if let tblView = tableView {
//code
}
and
if let theIndexPath = indexPath {
//code
}
So ... in order not to change my entire project, I overrided the functions like this:
override func tableView(tableView: UITableView?, didSelectRowAtIndexPath indexPath: NSIndexPath?){
and everything worked fine, except that with my changes the ProfileTableViewController doesn't conform UITableViewDataSource, and I've had to remove the data source from the class definition.

Resources